From: jacob Date: Sun, 19 Dec 2004 22:54:41 +0000 (+0000) Subject: import older libsysio snapshot. X-Git-Tag: v1_7_100~1^6~3 X-Git-Url: https://git.whamcloud.com/?p=fs%2Flustre-release.git;a=commitdiff_plain;h=b8292c00324fbe9a25910ce53d03569186ea3e2c import older libsysio snapshot. --- b8292c00324fbe9a25910ce53d03569186ea3e2c diff --git a/libsysio/AUTHORS b/libsysio/AUTHORS new file mode 100644 index 0000000..7293307 --- /dev/null +++ b/libsysio/AUTHORS @@ -0,0 +1 @@ +Lee Ward diff --git a/libsysio/COPYING b/libsysio/COPYING new file mode 100644 index 0000000..2bb5b6e --- /dev/null +++ b/libsysio/COPYING @@ -0,0 +1,502 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + 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. + + 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. + + 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. + + 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. + + 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. + + 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. + + 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. + + 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 + + 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. + + + Copyright (C) + + 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. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! diff --git a/libsysio/ChangeLog b/libsysio/ChangeLog new file mode 100644 index 0000000..126c27f --- /dev/null +++ b/libsysio/ChangeLog @@ -0,0 +1,31 @@ +Sat Feb 22 10:32:10 EST 2003 + Created +--- + +*Added mount() api call to support sub-mounts. + +*Added rudimentary automounts per the namespace chapter in the "Lustre +Architecture Reference". Note, full URI support is not implemented. See +the README for details. + +Think I have it going for simultaneous 32/64 bit support. Together with +the nagging build for test_stat. + +*Miscellaneous bugs fixed. + +--- +Lee -- Sat Mar 22 15:01:45 EST 2003 + +*Added "incore" file system. An in-memory file system solving boot-strap +and other annoying little chicken-and-the-egg problems. + +*Added support for devices + +*Added support for accessing the pre-opened standard file descriptors 0, 1, +and 2 via the stdfd device driver (major number 0, minor 0, 1, and 2). + +--- +Lee -- Mon Jan 26 11:26:14 EST 2004 + +*Altered the internal interface to pass the xtvec (see .../include/xtio.h) in +order to support strided-io. diff --git a/libsysio/Makefile.am b/libsysio/Makefile.am new file mode 100644 index 0000000..11e6e3d --- /dev/null +++ b/libsysio/Makefile.am @@ -0,0 +1,91 @@ +AUTOMAKE_OPTIONS=1.6 + +if WITH_TESTS +TESTDIR = tests +else +TESTDIR = +endif + +include $(top_srcdir)/src/module.mk +include $(top_srcdir)/include/module.mk +include $(top_srcdir)/tests/module.mk +include $(top_srcdir)/dev/stdfd/module.mk +include $(top_srcdir)/drivers/incore/module.mk +include $(top_srcdir)/drivers/native/module.mk +include $(top_srcdir)/drivers/yod/module.mk +include $(top_srcdir)/drivers/sockets/module.mk + +lib_LIBRARIES = ${LIBBUILD_DIR}/libsysio.a + +if WITH_STDFD_DEV +OPTIONAL_STDFD_SRCS = $(STDFD_SRCS) +else +OPTIONAL_STDFD_SRCS = +endif + +if WITH_INCORE_DRIVER +OPTIONAL_INCORE_SRCS = $(INCORE_SRCS) +else +OPTIONAL_INCORE_SRCS = +endif + +if WITH_NATIVE_DRIVER +OPTIONAL_NATIVE_SRCS = $(NATIVE_SRCS) +else +OPTIONAL_NATIVE_SRCS = +endif + +if WITH_SOCKETS_DRIVER +OPTIONAL_SOCKETS_SRCS = $(SOCKETS_SRCS) +else +OPTIONAL_SOCKETS_SRCS = +endif + +if WITH_CPLANT_YOD +OPTIONAL_YOD_SRCS = $(YOD_SRCS) +else +OPTIONAL_YOD_SRCS = +endif + +if WITH_LUSTRE_HACK +OPTIONAL_LUSTRE_SRCDIR_SRCS = $(LUSTRE_SRCDIR_SRCS) +# it would be better that let configure script check this +AM_CFLAGS = -fPIC +else +OPTIONAL_LUSTRE_SRCDIR_SRCS = +endif + +__LIBBUILD_DIR__libsysio_a_SOURCES = \ + $(SRCDIR_SRCS) \ + $(OPTIONAL_LUSTRE_SRCDIR_SRCS) \ + $(OPTIONAL_STDFD_SRCS) \ + $(OPTIONAL_INCORE_SRCS) \ + $(OPTIONAL_SOCKETS_SRCS) \ + $(OPTIONAL_NATIVE_SRCS) \ + $(OPTIONAL_YOD_SRCS) + +include $(top_srcdir)/Rules.make + +EXTRA_DIST = Rules.make misc/init-env.sh $(TESTS_EXTRA) $(SRCDIR_EXTRA) \ + $(INCLUDE_EXTRA) $(STDFD_EXTRA) $(INCORE_EXTRA) \ + $(SOCKETS_EXTRA) $(NATIVE_EXTRA) $(YOD_EXTRA) + +AM_CPPFLAGS += ${YOD_DRIVER_FLAGS} + +really-clean: testsclean maintainer-clean + -rm -rf autom4te-2.53.cache + -rm -rf .deps + -rm -f Makefile.in + -rm -f compile depcomp INSTALL install-sh missing mkinstalldirs \ + configure aclocal.m4 + -rm -f config.guess config.sub + -rm -rf $(LIBBUILD_DIR) + -rm -f libsysio*.tar.gz + cd $(TESTDIR); rm -rf Makefile Makefile.in .deps + +tests: $(lib_LIBRARIES) FORCE + cd $(TESTDIR); make +testsclean: FORCE + cd $(TESTDIR); make clean +clean: testsclean clean-am +FORCE: diff --git a/libsysio/NEWS b/libsysio/NEWS new file mode 100644 index 0000000..e69de29 diff --git a/libsysio/README b/libsysio/README new file mode 100644 index 0000000..76b9b97 --- /dev/null +++ b/libsysio/README @@ -0,0 +1,66 @@ +Build +----- + +To bootstrap configuration: + +sh autogen.sh +./configure [options] + +Without the supported "--with" options only the core sysio library is +built. + +Option --with-native-driver=yes will cause the "native" host name space test +driver to be enabled and made available in drivers/native/libsysio_native.a +when built. This is set by default; Use "no" to disable. + +Option --with-tests=yes will cause the test programs in the tests directory +to be enabled. This is set by default; Use "no" to disable. + +Option --with-automount= will cause automount support +to be included. If 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: + + +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: + +: + +Then the description is mounted on the directory containing the +special automount file and being used as the parent in the lookup. If the +mount is successful, the parent is replaced with the newly mounted directory +and processing continues. If the mount fails, or the automount file +does not exist or cannot be read, everything continues as though the operation +had never been attempted. + +File systems, or volumes, or file-sets, or whatever they are called, that +have been automounted may also be automatically unmounted when resource +is required. They are not on a timer, unless the file system driver implements +one for them. They just disappear as resource is needed elsewhere. As they +were automatically mounted to begin with, they should re-establish as needed, +transparently. + +REDSTORM +-------- + +The following works for me: + +#!/bin/sh + +export CFLAGS="-DREDSTORM -nostdinc -isystem /home/lee/REDSTORM/catamount/computeincs/i386 -isystem /home/lee/REDSTORM/catamount/include -g -W -Wall -ansi" + +sh configure --with-autmount=".mount" --with-native=yes --with-incore-yes --with-stdfd=yes --with-tests=yes diff --git a/libsysio/Rules.make b/libsysio/Rules.make new file mode 100644 index 0000000..45db68c --- /dev/null +++ b/libsysio/Rules.make @@ -0,0 +1,18 @@ + +if WITH_STDFD_DEV +STDFD_DEV_CPPFLAGS =-DSTDFD_DEV=1 -I$(top_srcdir)/dev/stdfd +else +STFD_DEV_CPPFLAGS = +endif + +if WITH_SOCKETS_DRIVER +SOCKETS_CPPFLAGS=-DWITH_SOCKETS=1 +else +SOCKETS_CPPFLAGS= +endif + +DEV_CPPFLAGS = $(STDFD_DEV_CPPFLAGS) + +AM_CPPFLAGS = \ + $(AUTOMOUNT) $(ZERO_SUM_MEMORY) $(DEV_CPPFLAGS) $(SOCKETS_CPPFLAGS) \ + -I$(top_srcdir)/include diff --git a/libsysio/autogen.sh b/libsysio/autogen.sh new file mode 100755 index 0000000..81ad5b6 --- /dev/null +++ b/libsysio/autogen.sh @@ -0,0 +1,5 @@ +#!/bin/sh + +aclocal && +automake --add-missing --copy && +${AUTOCONF:-autoconf} diff --git a/libsysio/configure.in b/libsysio/configure.in new file mode 100644 index 0000000..9f83269 --- /dev/null +++ b/libsysio/configure.in @@ -0,0 +1,427 @@ +AC_INIT(libsysio, 0.1) + +AC_CANONICAL_HOST + +case "$host_os" in + linux*) + ;; + *) + AC_MSG_WARN('***' ${host_os}: Unsupported OS target) + ;; +esac + +AM_INIT_AUTOMAKE([subdir-objects]) +AM_PROG_CC_C_O + +AC_PROG_CC +AC_PROG_RANLIB +AC_PROG_MAKE_SET +AC_HEADER_STDC +AC_HEADER_STAT +AC_HEADER_TIME + +have_lib_dir=yes; +AC_ARG_WITH(lib-dir, + AC_HELP_STRING([--with-lib-dir=], + [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@<:@=@:>@], + [with automounts @<:@=.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=], + [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 +#include +#include ], [ +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 +#include +#include ], [ +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 +#include +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 +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 +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 ], +[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 ], +[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 </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 </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< conftest1.c <&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 </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 </dev/null; then + sysio_asm_weakext_directive=yes + else + sysio_asm_weakext_directive=no + fi + rm -f conftest*]) +fi # no .weak + +if test x$sysio_asm_weak_directive = xyes; then + AC_DEFINE(HAVE_ASM_WEAK_DIRECTIVE) +fi +if test x$sysio_asm_weakext_directive = xyes; then + AC_DEFINE(HAVE_ASM_WEAKEXT_DIRECTIVE) +fi + +AC_OUTPUT( + Makefile + tests/Makefile) + diff --git a/libsysio/dev/stdfd/module.mk b/libsysio/dev/stdfd/module.mk new file mode 100644 index 0000000..ad034fb --- /dev/null +++ b/libsysio/dev/stdfd/module.mk @@ -0,0 +1,2 @@ +STDFD_SRCS = dev/stdfd/stdfd.c +STDFD_EXTRA = dev/stdfd/stdfd.h dev/stdfd/module.mk diff --git a/libsysio/dev/stdfd/stdfd.c b/libsysio/dev/stdfd/stdfd.c new file mode 100644 index 0000000..5a14e8b --- /dev/null +++ b/libsysio/dev/stdfd/stdfd.c @@ -0,0 +1,214 @@ +/* + * This Cplant(TM) source code is the property of Sandia National + * Laboratories. + * + * This Cplant(TM) source code is copyrighted by Sandia National + * Laboratories. + * + * The redistribution of this Cplant(TM) source code is subject to the + * terms of the GNU Lesser General Public License + * (see cit/LGPL or http://www.gnu.org/licenses/lgpl.html) + * + * Cplant(TM) Copyright 1998-2003 Sandia Corporation. + * Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive + * license for use of this work by or on behalf of the US Government. + * Export of this program may require a license from the United States + * Government. + */ + +/* + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Questions or comments about this library should be sent to: + * + * Lee Ward + * Sandia National Laboratories, New Mexico + * P.O. Box 5800 + * Albuquerque, NM 87185-1110 + * + * lee@sandia.gov + */ + +#ifdef __linux__ +#define _BSD_SOURCE +#endif + +#include +#include +#include +#include +#include +#include + +#include "sysio.h" +#include "inode.h" +#include "dev.h" + +#include "stdfd.h" + +#ifdef CPLANT_YOD +#include +#include "cplant-yod.h" +#define dowrite(f, b, n) write_yod(f, b, n) +#define doread(f, b, n) read_yod(f, b, n) +#else +#define dowrite(f, b, n) syscall(SYS_write, f, b, n) +#define doread(f, b, n) syscall(SYS_read, f, b, n) +#endif + +/* + * Pre-opened standard file descriptors driver. + */ + +static int stdfd_open(struct pnode *pno, int flags, mode_t mode); +static int stdfd_close(struct inode *ino); +static int stdfd_read(struct inode *ino, struct ioctx *ioctx); +static int stdfd_write(struct inode *ino, struct ioctx *ioctx); +static int stdfd_iodone(struct ioctx *ioctx); +static int stdfd_datasync(struct inode *ino); +static int stdfd_ioctl(struct inode *ino, + unsigned long int request, + va_list ap); + +int +_sysio_stdfd_init() +{ + struct inode_ops stdfd_operations; + + stdfd_operations = _sysio_nodev_ops; + stdfd_operations.inop_open = stdfd_open; + stdfd_operations.inop_close = stdfd_close; + stdfd_operations.inop_read = stdfd_read; + stdfd_operations.inop_write = stdfd_write; + stdfd_operations.inop_iodone = stdfd_iodone; + stdfd_operations.inop_datasync = stdfd_datasync; + stdfd_operations.inop_ioctl = stdfd_ioctl; + + return _sysio_char_dev_register(SYSIO_C_STDFD_MAJOR, + "stdfd", + &stdfd_operations); +} + +static int +stdfd_open(struct pnode *pno __IS_UNUSED, + int flags __IS_UNUSED, + mode_t mode __IS_UNUSED) +{ + + return 0; +} + +static int +stdfd_close(struct inode *ino __IS_UNUSED) +{ + + return 0; +} + +static int +doio(ssize_t (*f)(void *, size_t, _SYSIO_OFF_T, struct inode *), + struct inode *ino, + struct ioctx *ioctx) +{ + + if (ioctx->ioctx_xtvlen != 1) { + /* + * No scatter/gather to "file" address space (we're not + * seekable) and "nowhere" makes no sense. + */ + return -EINVAL; + } + ioctx->ioctx_cc = + _sysio_doio(ioctx->ioctx_xtv, ioctx->ioctx_xtvlen, + ioctx->ioctx_iov, ioctx->ioctx_iovlen, + (ssize_t (*)(void *, size_t, _SYSIO_OFF_T, void *))f, + ino); + if (ioctx->ioctx_cc < 0) { + ioctx->ioctx_errno = -ioctx->ioctx_cc; + ioctx->ioctx_cc = -1; + } + return 0; +} + +static ssize_t +stdfd_read_simple(void *buf, + size_t nbytes, + _SYSIO_OFF_T off __IS_UNUSED, + struct inode *ino) +{ + + int fd = SYSIO_MINOR_DEV(ino->i_rdev); + + return doread(fd, buf, nbytes); +} + +static int +stdfd_read(struct inode *ino, struct ioctx *ioctx) +{ + + return doio(stdfd_read_simple, ino, ioctx); +} + +static ssize_t +stdfd_write_simple(const void *buf, + size_t nbytes, + _SYSIO_OFF_T off __IS_UNUSED, + struct inode *ino) +{ + int fd = SYSIO_MINOR_DEV(ino->i_rdev); + + return dowrite(fd, buf, nbytes); +} + +static int +stdfd_write(struct inode *ino, struct ioctx *ioctx) +{ + + return doio((ssize_t (*)(void *, + size_t, + _SYSIO_OFF_T, + struct inode *))stdfd_write_simple, + ino, + ioctx); +} + +static int +stdfd_iodone(struct ioctx *iocp __IS_UNUSED) +{ + + /* + * It's always done in this driver. It completed when posted. + */ + return 1; +} + +static int +stdfd_datasync(struct inode *ino __IS_UNUSED) +{ + + /* + * We don't buffer, so nothing to do. + */ + return 0; +} + +static int +stdfd_ioctl(struct inode *ino __IS_UNUSED, + unsigned long int request __IS_UNUSED, + va_list ap __IS_UNUSED) +{ + + return -ENOTTY; +} diff --git a/libsysio/dev/stdfd/stdfd.h b/libsysio/dev/stdfd/stdfd.h new file mode 100644 index 0000000..3bac7c1 --- /dev/null +++ b/libsysio/dev/stdfd/stdfd.h @@ -0,0 +1,50 @@ +/* + * This Cplant(TM) source code is the property of Sandia National + * Laboratories. + * + * This Cplant(TM) source code is copyrighted by Sandia National + * Laboratories. + * + * The redistribution of this Cplant(TM) source code is subject to the + * terms of the GNU Lesser General Public License + * (see cit/LGPL or http://www.gnu.org/licenses/lgpl.html) + * + * Cplant(TM) Copyright 1998-2003 Sandia Corporation. + * Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive + * license for use of this work by or on behalf of the US Government. + * Export of this program may require a license from the United States + * Government. + */ + +/* + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Questions or comments about this library should be sent to: + * + * Lee Ward + * Sandia National Laboratories, New Mexico + * P.O. Box 5800 + * Albuquerque, NM 87185-1110 + * + * lee@sandia.gov + */ + +/* + * Std{in,out,err} pseudo-device-driver support. + */ + +#define SYSIO_C_STDFD_MAJOR 0 + +extern int _sysio_stdfd_init(void); diff --git a/libsysio/drivers/incore/README b/libsysio/drivers/incore/README new file mode 100644 index 0000000..2f8c4b8 --- /dev/null +++ b/libsysio/drivers/incore/README @@ -0,0 +1,27 @@ +This "incore" file system driver is a self-contained file system. It does +not use any resource external to the node. + +It is primarily intended for enabling an efficient compute-node bootstrap. It +might also be useful for a very small scratch file system, holding device +files, and the like. + +The root directory i-node is manufactured on the fly. The source specification +for the mount() call should be something like: + + ++ + +Where: + are the directory permissions masked by 0777 + Note -- no umask is applied. + should be the owner's uid + should be the owner's gid + +Most operations are supported, with the notable exception of symbolic +links. + +In the implementation, the driver is really set up to export most +useful symbols without polluting the name space or contending with +other public symbols. However, the symbols are not yet exported. If +we ever require a proc-fs style file system, this could be very useful +provided a little extra work is done to allow other drivers to overload +some operations. Particularly the file ops, I would think. diff --git a/libsysio/drivers/incore/fs_incore.c b/libsysio/drivers/incore/fs_incore.c new file mode 100644 index 0000000..b6eb1c0 --- /dev/null +++ b/libsysio/drivers/incore/fs_incore.c @@ -0,0 +1,1693 @@ +/* + * This Cplant(TM) source code is the property of Sandia National + * Laboratories. + * + * This Cplant(TM) source code is copyrighted by Sandia National + * Laboratories. + * + * The redistribution of this Cplant(TM) source code is subject to the + * terms of the GNU Lesser General Public License + * (see cit/LGPL or http://www.gnu.org/licenses/lgpl.html) + * + * Cplant(TM) Copyright 1998-2003 Sandia Corporation. + * Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive + * license for use of this work by or on behalf of the US Government. + * Export of this program may require a license from the United States + * Government. + */ + +/* + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Questions or comments about this library should be sent to: + * + * Lee Ward + * Sandia National Laboratories, New Mexico + * P.O. Box 5800 + * Albuquerque, NM 87185-1110 + * + * lee@sandia.gov + */ + +#ifdef __linux__ +#define _BSD_SOURCE +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef _HAVE_STATVFS +#include +#endif +#include + +#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: + * + * ++ + */ + 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); +} diff --git a/libsysio/drivers/incore/fs_incore.h b/libsysio/drivers/incore/fs_incore.h new file mode 100644 index 0000000..84fa631 --- /dev/null +++ b/libsysio/drivers/incore/fs_incore.h @@ -0,0 +1,48 @@ +/* + * This Cplant(TM) source code is the property of Sandia National + * Laboratories. + * + * This Cplant(TM) source code is copyrighted by Sandia National + * Laboratories. + * + * The redistribution of this Cplant(TM) source code is subject to the + * terms of the GNU Lesser General Public License + * (see cit/LGPL or http://www.gnu.org/licenses/lgpl.html) + * + * Cplant(TM) Copyright 1998-2003 Sandia Corporation. + * Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive + * license for use of this work by or on behalf of the US Government. + * Export of this program may require a license from the United States + * Government. + */ + +/* + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Questions or comments about this library should be sent to: + * + * Lee Ward + * Sandia National Laboratories, New Mexico + * P.O. Box 5800 + * Albuquerque, NM 87185-1110 + * + * lee@sandia.gov + */ + +/* + * Native file system driver support. + */ + +extern int _sysio_incore_init(void); diff --git a/libsysio/drivers/incore/module.mk b/libsysio/drivers/incore/module.mk new file mode 100644 index 0000000..140d69b --- /dev/null +++ b/libsysio/drivers/incore/module.mk @@ -0,0 +1,2 @@ +INCORE_SRCS = drivers/incore/fs_incore.c +INCORE_EXTRA = drivers/incore/fs_incore.h drivers/incore/module.mk diff --git a/libsysio/drivers/native/fs_native.c b/libsysio/drivers/native/fs_native.c new file mode 100644 index 0000000..c66c1ed --- /dev/null +++ b/libsysio/drivers/native/fs_native.c @@ -0,0 +1,1722 @@ +/* + * This Cplant(TM) source code is the property of Sandia National + * Laboratories. + * + * This Cplant(TM) source code is copyrighted by Sandia National + * Laboratories. + * + * The redistribution of this Cplant(TM) source code is subject to the + * terms of the GNU Lesser General Public License + * (see cit/LGPL or http://www.gnu.org/licenses/lgpl.html) + * + * Cplant(TM) Copyright 1998-2004 Sandia Corporation. + * Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive + * license for use of this work by or on behalf of the US Government. + * Export of this program may require a license from the United States + * Government. + */ + +/* + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Questions or comments about this library should be sent to: + * + * Lee Ward + * Sandia National Laboratories, New Mexico + * P.O. Box 5800 + * Albuquerque, NM 87185-1110 + * + * lee@sandia.gov + */ + +#ifdef __linux__ +#define _BSD_SOURCE +#endif + +#include /* for NULL */ +#include +#ifdef __linux__ +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#if 0 +#include +#endif +#ifdef _HAVE_STATVFS +#include +#include +#endif +#include +#include +#if !(defined(REDSTORM) || defined(MAX_IOVEC)) +#include +#endif + +#include "sysio.h" +#include "fs.h" +#include "mount.h" +#include "inode.h" +#include "xtio.h" + +#include "fs_native.h" + +#ifdef REDSTORM +#include +#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 +#else /* !defined(_LARGEFILE64_SOURCE) */ +#define DIR_CVT_64 0 +#endif /* defined(_LARGEFILE64_SOURCE) */ +#else /* catch-none */ +#error No usable directory fill entries interface available +#endif + +/* + * Local host file system driver. + */ + +#if defined(ALPHA_LINUX) + +/* stat struct from asm/stat.h, as returned + * by alpha linux kernel + */ +struct __native_stat { + unsigned int st_dev; + unsigned int st_ino; + unsigned int st_mode; + unsigned int st_nlink; + unsigned int st_uid; + unsigned int st_gid; + unsigned int st_rdev; + long st_size; + unsigned long st_atime; + unsigned long st_mtime; + unsigned long st_ctime; + unsigned int st_blksize; + int st_blocks; + unsigned int st_flags; + unsigned int st_gen; +}; + +#define COPY_STAT(src, dest) \ +do { \ + memset((dest), 0, sizeof((*dest))); \ + (dest)->st_dev = (src)->st_dev; \ + (dest)->st_ino = (src)->st_ino; \ + (dest)->st_mode = (src)->st_mode; \ + (dest)->st_nlink = (src)->st_nlink; \ + (dest)->st_uid = (src)->st_uid; \ + (dest)->st_gid = (src)->st_gid; \ + (dest)->st_rdev = (src)->st_rdev; \ + (dest)->st_size = (src)->st_size; \ + (dest)->st_atime = (src)->st_atime; \ + (dest)->st_mtime = (src)->st_mtime; \ + (dest)->st_ctime = (src)->st_ctime; \ + (dest)->st_blksize = (src)->st_blksize; \ + (dest)->st_blocks = (src)->st_blocks; \ + (dest)->st_flags = (src)->st_flags; \ + (dest)->st_gen = (src)->st_gen; \ +} while (0); + +#else +#define __native_stat intnl_stat +#define COPY_STAT(src, dest) *(dest) = *(src) +#endif + +#if defined(USE_NATIVE_STAT) +#define __SYS_STAT SYS_lstat +#define __SYS_FSTAT SYS_fstat +#define __SYS_TRUNCATE SYS_truncate +#define __SYS_FTRUNCATE SYS_ftruncate +#else +#define __SYS_STAT SYS_lstat64 +#define __SYS_FSTAT SYS_fstat64 +#define __SYS_TRUNCATE SYS_truncate64 +#define __SYS_FTRUNCATE SYS_ftruncate64 +#endif + +#if defined(USE_NATIVE_FDATASYNC) +#define __SYS_FDATASYNC SYS_osf_fdatasync +#else +#define __SYS_FDATASYNC SYS_fdatasync +#endif + +#if defined(USE_NATIVE_UTIME) +#define __SYS_UTIME SYS_utimes +#else +#define __SYS_UTIME SYS_utime +#endif + +/* + * Native file identifiers format. + */ +struct native_inode_identifier { + dev_t dev; /* device number */ + ino_t ino; /* i-number */ +#ifdef HAVE_GENERATION + unsigned int gen; /* generation number */ +#endif +}; + +/* + * Driver-private i-node information we keep about local host file + * system objects. + */ +struct native_inode { + unsigned + ni_seekok : 1; /* can seek? */ + struct native_inode_identifier ni_ident; /* unique identifier */ + struct file_identifier ni_fileid; /* ditto */ + int ni_fd; /* host fildes */ + int ni_oflags; /* flags, from open */ + unsigned ni_nopens; /* soft ref count */ + _SYSIO_OFF_T ni_fpos; /* current pos */ +}; + +/* + * Native IO path arguments. + */ +struct native_io { + char nio_op; /* 'r' or 'w' */ + struct native_inode *nio_nino; /* native ino */ +}; + +static int native_inop_lookup(struct pnode *pno, + struct inode **inop, + struct intent *intnt, + const char *path); +static int native_inop_getattr(struct pnode *pno, + struct inode *ino, + struct intnl_stat *stbuf); +static int native_inop_setattr(struct pnode *pno, + struct inode *ino, + unsigned mask, + struct intnl_stat *stbuf); +static ssize_t native_getdirentries(struct inode *ino, + char *buf, + size_t nbytes, + _SYSIO_OFF_T *basep); +static int native_inop_mkdir(struct pnode *pno, mode_t mode); +static int native_inop_rmdir(struct pnode *pno); +static int native_inop_symlink(struct pnode *pno, const char *data); +static int native_inop_readlink(struct pnode *pno, char *buf, size_t bufsiz); +static int native_inop_open(struct pnode *pno, int flags, mode_t mode); +static int native_inop_close(struct inode *ino); +static int native_inop_link(struct pnode *old, struct pnode *new); +static int native_inop_unlink(struct pnode *pno); +static int native_inop_rename(struct pnode *old, struct pnode *new); +static int native_inop_read(struct inode *ino, struct ioctx *ioctx); +static int native_inop_write(struct inode *ino, struct ioctx *ioctx); +static _SYSIO_OFF_T native_inop_pos(struct inode *ino, _SYSIO_OFF_T off); +static int native_inop_iodone(struct ioctx *ioctx); +static int native_inop_fcntl(struct inode *ino, int cmd, va_list ap); +static int native_inop_sync(struct inode *ino); +static int native_inop_datasync(struct inode *ino); +static int native_inop_ioctl(struct inode *ino, + unsigned long int request, + va_list ap); +static int native_inop_mknod(struct pnode *pno, mode_t mode, dev_t dev); +#ifdef _HAVE_STATVFS +static int native_inop_statvfs(struct pnode *pno, + struct inode *ino, + struct intnl_statvfs *buf); +#endif +static void native_inop_gone(struct inode *ino); + +static struct inode_ops native_i_ops = { + native_inop_lookup, + native_inop_getattr, + native_inop_setattr, + native_getdirentries, + native_inop_mkdir, + native_inop_rmdir, + native_inop_symlink, + native_inop_readlink, + native_inop_open, + native_inop_close, + native_inop_link, + native_inop_unlink, + native_inop_rename, + native_inop_read, + native_inop_write, + native_inop_pos, + native_inop_iodone, + native_inop_fcntl, + native_inop_sync, + native_inop_datasync, + native_inop_ioctl, + native_inop_mknod, +#ifdef _HAVE_STATVFS + native_inop_statvfs, +#endif + native_inop_gone +}; + +static int native_fsswop_mount(const char *source, + unsigned flags, + const void *data, + struct pnode *tocover, + struct mount **mntp); + +static struct fssw_ops native_fssw_ops = { + native_fsswop_mount +}; + +static void native_fsop_gone(struct filesys *fs); + +static struct filesys_ops native_inodesys_ops = { + native_fsop_gone, +}; + +/* + * This example driver plays a strange game. It maintains a private, + * internal mount -- It's own separate, rooted, name space. The local + * file system's entire name space is available via this tree. + * + * This simplifies the implementation. At mount time, we need to generate + * a path-node to be used as a root. This allows us to look up the needed + * node in the host name space and leverage a whole lot of support from + * the system. + */ +static struct mount *native_internal_mount = NULL; + +/* + * Given i-node, return driver private part. + */ +#define I2NI(ino) ((struct native_inode *)((ino)->i_private)) + +/* + * stat -- by path. + */ +static int +native_stat(const char *path, struct intnl_stat *buf) +{ + int err; + struct __native_stat stbuf; + + err = syscall(__SYS_STAT, path, &stbuf); + if (err) + err = -errno; + COPY_STAT(&stbuf, buf); + + return err; +} + +/* + * stat -- by fildes + */ +static int +native_fstat(int fd, struct intnl_stat *buf) +{ + int err; + struct __native_stat stbuf; + + err = syscall(__SYS_FSTAT, fd, &stbuf); + if (err) + err = -errno; + COPY_STAT(&stbuf, buf); + + return err; +} + +/* + * Introduce an i-node to the system. + */ +static struct inode * +native_i_new(struct filesys *fs, struct intnl_stat *buf) +{ + struct native_inode *nino; + struct inode *ino; + + nino = malloc(sizeof(struct native_inode)); + if (!nino) + return NULL; + bzero(&nino->ni_ident, sizeof(nino->ni_ident)); + nino->ni_ident.dev = buf->st_dev; + nino->ni_ident.ino = buf->st_ino; +#ifdef HAVE_GENERATION + nino->ni_ident.gen = buf->st_gen; +#endif + nino->ni_fileid.fid_data = &nino->ni_ident; + nino->ni_fileid.fid_len = sizeof(nino->ni_ident); + nino->ni_fd = -1; + nino->ni_oflags = 0; + nino->ni_nopens = 0; + nino->ni_fpos = 0; + ino = + _sysio_i_new(fs, + &nino->ni_fileid, +#ifndef AUTOMOUNT_FILE_NAME + buf->st_mode & S_IFMT, +#else + buf->st_mode, /* all of the bits! */ +#endif + 0, + 0, + &native_i_ops, + nino); + if (!ino) + free(nino); + return ino; +} + +/* + * Initialize this driver. + */ +int +_sysio_native_init() +{ + + /* + * Capture current process umask and reset our process umask to + * zero. All permission bits to open/creat/setattr are absolute -- + * They've already had a umask applied, when appropriate. + */ + _sysio_umask = syscall(SYS_umask, 0); + + return _sysio_fssw_register("native", &native_fssw_ops); +} + +/* + * Create private, internal, view of the hosts name space. + */ +static int +create_internal_namespace() +{ + int err; + struct mount *mnt; + struct inode *rootino; + struct pnode_base *rootpb; + static struct qstr noname = { NULL, 0, 0 }; + struct filesys *fs; + struct intnl_stat stbuf; + + if (native_internal_mount) { + /* + * Reentered! + */ + abort(); + } + + /* + * We maintain an artificial, internal, name space in order to + * have access to fully qualified path names in the various routines. + * Initialize that name space now. + */ + mnt = NULL; + rootino = NULL; + rootpb = NULL; + fs = _sysio_fs_new(&native_inodesys_ops, 0, NULL); + if (!fs) { + err = -ENOMEM; + goto error; + } + + /* + * Get root i-node. + */ + err = native_stat("/", &stbuf); + if (err) + goto error; + rootino = native_i_new(fs, &stbuf); + if (!rootino) { + err = -ENOMEM; + goto error; + } + + /* + * Generate base path-node for root. + */ + rootpb = _sysio_pb_new(&noname, NULL, rootino); + if (!rootpb) { + err = -ENOMEM; + goto error; + } + + /* + * Mount it. This name space is disconnected from the + * rest of the system -- Only available within this driver. + */ + err = _sysio_do_mount(fs, rootpb, 0, NULL, &mnt); + if (err) + goto error; + + native_internal_mount = mnt; + return 0; +error: + if (mnt) { + if (_sysio_do_unmount(mnt) != 0) + abort(); + fs = NULL; + rootpb = NULL; + rootino = NULL; + } + if (rootpb) + _sysio_pb_gone(rootpb); + if (fs) { + FS_RELE(fs); + _sysio_fs_gone(fs); + } + + return err; +} + +static int +native_fsswop_mount(const char *source, + unsigned flags, + const void *data __IS_UNUSED, + struct pnode *tocover, + struct mount **mntp) +{ + int err; + struct nameidata nameidata; + struct mount *mnt; + + /* + * Caller must use fully qualified path names when specifying + * the source. + */ + if (*source != '/') + return -ENOENT; + + if (!native_internal_mount) { + err = create_internal_namespace(); + if (err) + return err; + } + + /* + * Lookup the source in the internally maintained name space. + */ + ND_INIT(&nameidata, 0, source, native_internal_mount->mnt_root, NULL); + err = _sysio_path_walk(native_internal_mount->mnt_root, &nameidata); + if (err) + return err; + + /* + * Have path-node specified by the given source argument. Let the + * system finish the job, now. + */ + err = + _sysio_do_mount(native_internal_mount->mnt_fs, + nameidata.nd_pno->p_base, + flags, + tocover, + &mnt); + /* + * Release the internal name space pnode and clean up any + * aliases we might have generated. We really don't need to cache them + * as they are only used at mount time.. + */ + P_RELE(nameidata.nd_pno); + (void )_sysio_p_prune(native_internal_mount->mnt_root); + + if (!err) { + FS_REF(native_internal_mount->mnt_fs); + *mntp = mnt; + } + return err; +} + +static int +native_i_invalid(struct inode *inop, struct intnl_stat stbuf) +{ + /* + * Validate passed in inode against stat struct info + */ + struct native_inode *nino = I2NI(inop); + + if ((nino->ni_ident.dev != stbuf.st_dev || + nino->ni_ident.ino != stbuf.st_ino || +#ifdef HAVE_GENERATION + nino->ni_ident.gen != stbuf.st_gen || +#endif + ((inop)->i_mode & S_IFMT) != (stbuf.st_mode & S_IFMT)) || + (((inop)->i_rdev != stbuf.st_rdev) && + (S_ISCHR((inop)->i_mode) || S_ISBLK((inop)->i_mode)))) + return 1; + + return 0; +} + +/* + * Find, and validate, or create i-node by host-relative path. Returned i-node + * is referenced. + */ +static int +native_iget(struct filesys *fs, + const char *path, + struct inode **inop, + int forced) +{ + int err; + struct inode *ino; + struct intnl_stat stbuf; + struct native_inode_identifier ident; + struct file_identifier fileid; + + /* + * Get file status. + */ + err = native_stat(path, &stbuf); + if (err) { + *inop = NULL; + return err; + } + + /* + * Validate? + */ + if (*inop) { + if (!native_i_invalid(*inop, stbuf)) + return 0; + /* + * Invalidate. + */ + *inop = NULL; + } + + /* + * I-node is not already known. Find or create it. + */ + bzero(&ident, sizeof(ident)); + ident.dev = stbuf.st_dev; + ident.ino = stbuf.st_ino; +#ifdef HAVE_GENERATION + ident.gen = stbuf.st_gen; +#endif + fileid.fid_data = &ident; + fileid.fid_len = sizeof(ident); + ino = _sysio_i_find(fs, &fileid); + if (ino && forced) { + /* + * Insertion was forced but it's already present! + */ + if (native_i_invalid(ino, stbuf)) { + /* + * Cached inode has stale attrs + * make way for the new one + */ + I_GONE(ino); + ino = NULL; + } else + /* + * OK to reuse cached inode + */ + goto out; + } + + if (!ino) { + ino = native_i_new(fs, &stbuf); + if (!ino) + err = -ENOMEM; + } +out: + if (!err) + *inop = ino; + return err; +} + +/* + * Look up named object in host's name space by path. + */ +static int +native_path_lookup(struct filesys *fs, const char *path, struct inode **inop) +{ + + return native_iget(fs, path, inop, 0); +} + +/* + * Look up object by it's path node. + */ +static int +native_i_lookup(struct filesys *fs, struct pnode_base *pb, struct inode **inop) +{ + int err; + char *path; + + path = _sysio_pb_path(pb, '/'); + if (!path) + return -ENOMEM; + err = native_path_lookup(fs, path, inop); + free(path); + return err; +} + +static int +native_inop_lookup(struct pnode *pno, + struct inode **inop, + struct intent *intnt __IS_UNUSED, + const char *path __IS_UNUSED) +{ + int err; + + *inop = pno->p_base->pb_ino; + + /* + * Don't have an inode yet. Because we translate everything back to + * a single name space for the host, we will assume the object the + * caller is looking for has no existing alias in our internal + * name space. We don't see the same file on different mounts in the + * underlying host FS as the same file. + * + * The file identifier *will* be unique. It's got to have a different + * dev. + */ + err = native_i_lookup(pno->p_mount->mnt_fs, pno->p_base, inop); + if (err) + *inop = NULL; + return err; +} + +static int +native_inop_getattr(struct pnode *pno, struct inode *ino, struct intnl_stat *stbuf) +{ + char *path; + int err; + + path = NULL; + if (!ino || I2NI(ino)->ni_fd < 0) { + path = _sysio_pb_path(pno->p_base, '/'); + if (!path) + return -ENOMEM; + } + err = + path + ? native_stat(path, stbuf) + : native_fstat(I2NI(ino)->ni_fd, stbuf); + if (path) + free(path); + return err; +} + +static int +native_inop_setattr(struct pnode *pno, + struct inode *ino, + unsigned mask, + struct intnl_stat *stbuf) +{ + char *path; + int fd; + struct intnl_stat st; + int err; + + path = NULL; + fd = ino ? I2NI(ino)->ni_fd : -1; + if (fd < 0 || mask & (SETATTR_MTIME|SETATTR_ATIME)) { + if (!pno) + return -EEXIST; + path = _sysio_pb_path(pno->p_base, '/'); + if (!path) + return -ENOMEM; + } + + /* + * Get current status for undo. + */ + err = + fd < 0 + ? native_stat(path, &st) + : native_fstat(fd, &st); + if (err) + goto out; + + if (mask & SETATTR_MODE) { + mode_t mode; + + /* + * Alter permissions attribute. + */ + mode = stbuf->st_mode & 07777; + err = + fd < 0 + ? syscall(SYS_chmod, path, mode) + : syscall(SYS_fchmod, fd, mode); + if (err) + err = -errno; + } + if (err) + mask &= ~SETATTR_MODE; + else if (mask & (SETATTR_MTIME|SETATTR_ATIME)) { + struct utimbuf ut; + + /* + * Alter access and/or modify time attributes. + */ + ut.actime = st.st_atime; + ut.modtime = st.st_mtime; + if (mask & SETATTR_MTIME) + ut.modtime = stbuf->st_mtime; + if (mask & SETATTR_ATIME) + ut.actime = stbuf->st_atime; + err = syscall(__SYS_UTIME, path, &ut); + if (err) + err = -errno; + } + if (err) + mask &= ~(SETATTR_MTIME|SETATTR_ATIME); + else if (mask & (SETATTR_UID|SETATTR_GID)) { + + /* + * Alter owner and/or group identifiers. + */ + err = + fd < 0 + ? syscall(SYS_chown, + path, + mask & SETATTR_UID + ? stbuf->st_uid + : (uid_t )-1, + mask & SETATTR_GID + ? stbuf->st_gid + : (gid_t )-1) + : syscall(SYS_fchown, + fd, + mask & SETATTR_UID + ? stbuf->st_uid + : (uid_t )-1, + mask & SETATTR_GID + ? stbuf->st_gid + : (gid_t )-1); + if (err) + err = -errno; + } + if (err) + mask &= ~(SETATTR_UID|SETATTR_GID); + else if (mask & SETATTR_LEN) { + /* + * Do the truncate last. It can't be undone. + */ + (void )(fd < 0 + ? syscall(__SYS_TRUNCATE, path, stbuf->st_size) + : syscall(__SYS_FTRUNCATE, fd, stbuf->st_size)); + } + if (!err) + goto out; + /* + * Undo after error. Some or all of this might not work... We + * can but try. + */ + if (mask & (SETATTR_UID|SETATTR_GID)) { + (void )(fd < 0 + ? syscall(SYS_chown, + path, + mask & SETATTR_UID + ? st.st_uid + : (uid_t )-1, + mask & SETATTR_GID + ? st.st_gid + : (gid_t )-1) + : syscall(SYS_fchown, + fd, + mask & SETATTR_UID + ? st.st_uid + : (uid_t )-1, + mask & SETATTR_GID + ? st.st_gid + : (gid_t )-1)); + } + if (mask & (SETATTR_MTIME|SETATTR_ATIME)) { + struct utimbuf ut; + + ut.actime = st.st_atime; + ut.modtime = st.st_mtime; + (void )syscall(__SYS_UTIME, path, &ut); + } + if (mask & SETATTR_MODE) { + fd < 0 + ? syscall(SYS_chmod, path, st.st_mode & 07777) + : syscall(SYS_fchmod, fd, st.st_mode & 07777); + } +out: + if (path) + free(path); + return err; +} + +static int +native_pos(int fd, _SYSIO_OFF_T *offset, int whence) +{ + _SYSIO_OFF_T off; + + assert(fd >= 0); + assert(*offset >= 0); + + off = *offset; +#if _LARGEFILE64_SOURCE && defined(SYS__llseek) + { + int err; + err = + syscall(SYS__llseek, + (unsigned int)fd, + (unsigned int)(off >> 32), + (unsigned int)off, + &off, + whence); + if (err == -1) + return -errno; + } +#else + off = + syscall(SYS_lseek, + fd, + off, + whence); + if (off == -1) + return -errno; +#endif + *offset = off; + + return 0; +} + +static ssize_t +native_filldirentries(struct native_inode *nino, + char *buf, + size_t nbytes, + _SYSIO_OFF_T *basep) +{ + int err; + ssize_t cc; + + if (*basep < 0) + return -EINVAL; + +#if DIR_STREAMED + /* + * Stream-oriented access requires that we reposition prior to the + * fill call. + */ + if ((err = native_pos(nino->ni_fd, basep, SEEK_SET)) != 0) + return err; +#endif + nino->ni_fpos = *basep; + + cc = +#if defined(SYS_getdirentries) + syscall(SYS_getdirentries, + nino->ni_fd, + buf, + nbytes, + basep); +#elif defined(SYS_getdents64) + syscall(SYS_getdents64, nino->ni_fd, buf, nbytes); +#elif defined(SYS_getdents) + syscall(SYS_getdents, nino->ni_fd, buf, nbytes); +#endif + + if (cc < 0) + return -errno; +#if DIR_STREAMED + /* + * Stream-oriented access requires that we discover where we are + * after the call. + */ + *basep = 0; + if ((err = native_pos(nino->ni_fd, basep, SEEK_CUR)) != 0) + return err; +#endif + nino->ni_fpos = *basep; + return cc; +} + +static ssize_t +native_getdirentries(struct inode *ino, + char *buf, + size_t nbytes, + _SYSIO_OFF_T *basep) +{ + struct native_inode *nino = I2NI(ino); +#if DIR_CVT_64 + char *bp; + size_t count; + struct linux_dirent *ldp; + struct dirent64 *d64p; + size_t namlen; + size_t reclen; +#else +#define bp buf +#define count nbytes +#endif + ssize_t cc; + + assert(nino->ni_fd >= 0); + +#if DIR_CVT_64 + count = nbytes; + while (!(bp = malloc(count))) { + count /= 2; + if (count < sizeof(struct dirent)) + return -ENOMEM; + } +#endif + cc = native_filldirentries(nino, bp, count, basep); + if (cc < 0) { +#if DIR_CVT_64 + free(bp); +#endif + return cc; + } +#if DIR_CVT_64 + ldp = (struct linux_dirent *)bp; + d64p = (struct dirent64 *)buf; + for (;;) { + if (cc < 0 || (size_t )cc <= sizeof(*ldp)) + break; + namlen = strlen(ldp->ld_name); + reclen = sizeof(*d64p) - sizeof(d64p->d_name) + namlen + 1; + if (nbytes < reclen) + break; + d64p->d_ino = ldp->ld_ino; + d64p->d_off = ldp->ld_off; + d64p->d_reclen = + (((reclen + sizeof(long) - 1)) / sizeof(long)) * + sizeof(long); + if (nbytes < d64p->d_reclen) + d64p->d_reclen = reclen; + d64p->d_type = DT_UNKNOWN; /* you lose -- sorry. */ + (void )strncpy(d64p->d_name, ldp->ld_name, namlen); + *(d64p->d_name + namlen) = '\0'; + cc -= ldp->ld_reclen; + ldp = (struct linux_dirent *)((char *)ldp + ldp->ld_reclen); + nbytes -= d64p->d_reclen; + d64p = (struct dirent64 *)((char *)d64p + d64p->d_reclen); + } + free(bp); + if (d64p == (struct dirent64 *)buf && cc) + cc = -EINVAL; /* buf too small */ + cc = (char *)d64p - buf; +#else +#undef bp +#undef count +#endif + return cc; +} + +static int +native_inop_mkdir(struct pnode *pno, mode_t mode) +{ + char *path; + int err; + + path = _sysio_pb_path(pno->p_base, '/'); + if (!path) + return -ENOMEM; + + err = syscall(SYS_mkdir, path, mode); + if (err != 0) + err = -errno; + free(path); + return err; +} + +static int +native_inop_rmdir(struct pnode *pno) +{ + char *path; + int err; + + path = _sysio_pb_path(pno->p_base, '/'); + if (!path) + return -ENOMEM; + + err = syscall(SYS_rmdir, path); + if (err != 0) + err = -errno; + free(path); + return err; +} + +static int +native_inop_symlink(struct pnode *pno, const char *data) +{ + char *path; + int err; + + path = _sysio_pb_path(pno->p_base, '/'); + if (!path) + return -ENOMEM; + + err = syscall(SYS_symlink, data, path); + if (err != 0) + err = -errno; + free(path); + return err; +} + +static int +native_inop_readlink(struct pnode *pno, char *buf, size_t bufsiz) +{ + char *path; + int i; + + path = _sysio_pb_path(pno->p_base, '/'); + if (!path) + return -ENOMEM; + i = syscall(SYS_readlink, path, buf, bufsiz); + if (i < 0) + i = -errno; + free(path); + return i; +} + +static int +native_inop_open(struct pnode *pno, int flags, mode_t mode) +{ + struct native_inode *nino; + char *path; + int fd; + + path = _sysio_pb_path(pno->p_base, '/'); + if (!path) + return -ENOMEM; + + /* + * Whether the file is already open, or not, makes no difference. + * Want to always give the host OS a chance to authorize in case + * something has changed underneath us. + */ + if (flags & O_WRONLY) { + /* + * Promote write-only attempt to RW. + */ + flags &= ~O_WRONLY; + flags |= O_RDWR; + } +#ifdef O_LARGEFILE + flags |= O_LARGEFILE; +#endif + fd = syscall(SYS_open, path, flags, mode); + if (!pno->p_base->pb_ino && fd >= 0) { + int err; + + /* + * Success but we need to return an i-node. + */ + err = + native_iget(pno->p_mount->mnt_fs, + path, + &pno->p_base->pb_ino, + 1); + if (err) { + (void )syscall(SYS_close, fd); + if (err == -EEXIST) + abort(); + fd = err; + } + } + free(path); + if (fd < 0) + return -errno; + + /* + * Remember this new open. + */ + nino = I2NI(pno->p_base->pb_ino); + nino->ni_nopens++; + assert(nino->ni_nopens); + + if (nino->ni_fd >= 0) { + if ((nino->ni_oflags & O_RDWR) || + (flags & (O_RDONLY|O_WRONLY|O_RDWR)) == O_RDONLY) { + /* + * Keep existing. + */ + (void )syscall(SYS_close, fd); + return 0; + } + (void )syscall(SYS_close, nino->ni_fd); + } + /* + * Invariant; First open. Must init. + */ + nino->ni_fpos = 0; + nino->ni_fd = fd; + /* + * Need to know whether we can seek on this + * descriptor. + */ + nino->ni_seekok = + native_pos(nino->ni_fd, &nino->ni_fpos, SEEK_CUR) != 0 ? 0 : 1; + + return 0; +} + +static int +native_inop_close(struct inode *ino) +{ + struct native_inode *nino = I2NI(ino); + int err; + + if (nino->ni_fd < 0) + abort(); + + assert(nino->ni_nopens); + if (--nino->ni_nopens) { + /* + * Hmmm. We really don't need anything else. However, some + * filesystems try to implement a sync-on-close semantic. + * As this appears now, that is lost. Might want to change + * it somehow in the future? + */ + return 0; + } + + err = syscall(SYS_close, nino->ni_fd); + if (err) + return -errno; + + nino->ni_fd = -1; + nino->ni_fpos = 0; + return 0; +} + +static int +native_inop_link(struct pnode *old, struct pnode *new) +{ + int err; + char *opath, *npath; + + err = 0; + + opath = _sysio_pb_path(old->p_base, '/'); + npath = _sysio_pb_path(new->p_base, '/'); + if (!(opath && npath)) { + err = -ENOMEM; + goto out; + } + + err = syscall(SYS_link, opath, npath); + if (err != 0) + err = -errno; + +out: + if (opath) + free(opath); + if (npath) + free(npath); + + return err; +} + +static int +native_inop_unlink(struct pnode *pno) +{ + char *path; + int err = 0; + + path = _sysio_pb_path(pno->p_base, '/'); + if (!path) + return -ENOMEM; + + /* + * For this driver, unlink is easy with open files. Since the + * file remains open to the system, too, the descriptors are still + * valid. + * + * Other drivers will have some difficulty here as the entry in the + * file system name space must be removed without sacrificing access + * to the file itself. In NFS this is done with a mechanism referred + * to as a `silly delete'. The file is moved to a temporary name + * (usually .NFSXXXXXX, where the X's are replaced by the PID and some + * unique characters) in order to simulate the proper semantic. + */ + if (syscall(SYS_unlink, path) != 0) + err = -errno; + free(path); + return err; +} + +static int +native_inop_rename(struct pnode *old, struct pnode *new) +{ + int err; + char *opath, *npath; + + opath = _sysio_pb_path(old->p_base, '/'); + npath = _sysio_pb_path(new->p_base, '/'); + if (!(opath && npath)) { + err = -ENOMEM; + goto out; + } + + err = syscall(SYS_rename, opath, npath); + if (err != 0) + err = -errno; + +out: + if (opath) + free(opath); + if (npath) + free(npath); + + return err; +} + +static ssize_t +dopio(void *buf, size_t count, _SYSIO_OFF_T off, struct native_io *nio) +{ +#if defined(_LARGEFILE64_SOURCE) && \ + defined(SYS_pread64) && \ + defined(SYS_pwrite64) +#define _NATIVE_SYSCALL_PREAD SYS_pread64 +#define _NATIVE_SYSCALL_PWRITE SYS_pwrite64 +#else +#define _NATIVE_SYSCALL_PREAD SYS_pread +#define _NATIVE_SYSCALL_PWRITE SYS_pwrite +#endif + ssize_t cc; + + if (!(off == nio->nio_nino->ni_fpos || nio->nio_nino->ni_seekok)) + return -ESPIPE; + + if (!nio->nio_nino->ni_seekok) { + if (off != nio->nio_nino->ni_fpos) { + /* + * They've done a p{read,write} or somesuch. Can't + * seek on this descriptor so we err out now. + */ + errno = ESPIPE; + return -1; + } + cc = + syscall(nio->nio_op == 'r' ? SYS_read : SYS_write, + nio->nio_nino->ni_fd, + buf, + count); + if (cc > 0) + nio->nio_nino->ni_fpos += cc; + } else + cc = + syscall((nio->nio_op == 'r' + ? _NATIVE_SYSCALL_PREAD + : _NATIVE_SYSCALL_PWRITE), + nio->nio_nino->ni_fd, + buf, + count, + off); + + return cc; +#undef _NATIVE_SYSCALL_PREAD +#undef _NATIVE_SYSCALL_PWRITE +} + +static ssize_t +doiov(const struct iovec *iov, + int count, + _SYSIO_OFF_T off, + ssize_t limit, + struct native_io *nio) +{ + ssize_t cc; + +#if !(defined(REDSTORM) || defined(MAX_IOVEC)) +#define MAX_IOVEC INT_MAX +#endif + + if (count <= 0) + return -EINVAL; + + /* + * Avoid the reposition call if we're already at the right place. + * Allows us to access pipes and fifos. + */ + if (off != nio->nio_nino->ni_fpos) { + int err; + + err = native_pos(nio->nio_nino->ni_fd, &off, SEEK_SET); + if (err) + return err; + nio->nio_nino->ni_fpos = off; + } + + /* + * The {read,write}v is safe as this routine is only ever called + * by _sysio_enumerate_extents() and that routine is exact. It never + * passes iovectors including tails. + */ + cc = +#ifndef REDSTORM + count <= MAX_IOVEC + ? syscall(nio->nio_op == 'r' ? SYS_readv : SYS_writev, + nio->nio_nino->ni_fd, + iov, + count) + : +#endif + _sysio_enumerate_iovec(iov, + count, + off, + limit, + (ssize_t (*)(void *, + size_t, + _SYSIO_OFF_T, + void *))dopio, + nio); + if (cc < 0) + cc = -errno; + else + nio->nio_nino->ni_fpos += cc; + return cc; + +#if !(defined(REDSTORM) || defined(MAX_IOVEC)) +#undef MAX_IOVEC +#endif +} + +#if 0 +static int +lockop_all(struct native_inode *nino, + struct intnl_xtvec *xtv, + size_t count, + short op) +{ + struct flock flock; + int err; + + if (!count) + return -EINVAL; + flock.l_type = op; + flock.l_whence = SEEK_SET; + while (count--) { + flock.l_start = xtv->xtv_off; + flock.l_len = xtv->xtv_len; + xtv++; + err = + syscall( +#if !_LARGEFILE64_SOURCE + SYS_fcntl64 +#else + SYS_fcntl +#endif + , + nino->ni_fd, + F_SETLK, + &flock); + if (err != 0) + return -errno; + } + return 0; +} + +static int +order_xtv(const struct intnl_xtvec *xtv1, const struct intnl_xtvec *xtv2) +{ + + if (xtv1->xtv_off < xtv2->xtv_off) + return -1; + if (xtv1->xtv_off > xtv2->xtv_off) + return 1; + return 0; +} +#endif + +static int +doio(char op, struct ioctx *ioctx) +{ + struct native_inode *nino; +#if 0 + int dolocks; + struct intnl_xtvec *oxtv; + int err; +#endif + struct native_io arguments; + ssize_t cc; +#if 0 + struct intnl_xtvec *front, *rear, tmp; +#endif + + nino = I2NI(ioctx->ioctx_ino); +#if 0 + dolocks = ioctx->ioctx_xtvlen > 1 && nino->ni_seekok; + if (dolocks) { + /* + * Must lock the regions (in order!) since we can't do + * strided-IO as a single atomic operation. + */ + oxtv = malloc(ioctx->ioctx_xtvlen * sizeof(struct intnl_xtvec)); + if (!oxtv) + return -ENOMEM; + (void )memcpy(oxtv, + ioctx->ioctx_xtv, + ioctx->ioctx_xtvlen * sizeof(struct intnl_xtvec)); + qsort(oxtv, + ioctx->ioctx_xtvlen, + sizeof(struct intnl_xtvec), + (int (*)(const void *, const void *))order_xtv); + err = + lockop_all(nino, + oxtv, ioctx->ioctx_xtvlen, + op == 'r' ? F_RDLCK : F_WRLCK); + if (err) { + free(oxtv); + return err; + } + } +#endif + arguments.nio_op = op; + arguments.nio_nino = nino; + cc = + _sysio_enumerate_extents(ioctx->ioctx_xtv, ioctx->ioctx_xtvlen, + ioctx->ioctx_iov, ioctx->ioctx_iovlen, + (ssize_t (*)(const struct iovec *, + int, + _SYSIO_OFF_T, + ssize_t, + void *))doiov, + &arguments); +#if 0 + if (dolocks) { + /* + * Must unlock in reverse order. + */ + front = oxtv; + rear = front + ioctx->ioctx_xtvlen - 1; + while (front < rear) { + tmp = *front; + *front++ = *rear; + *rear-- = tmp; + } + if (lockop_all(nino, oxtv, ioctx->ioctx_xtvlen, F_UNLCK) != 0) + abort(); + free(oxtv); + } +#endif + if ((ioctx->ioctx_cc = cc) < 0) { + ioctx->ioctx_errno = -ioctx->ioctx_cc; + ioctx->ioctx_cc = -1; + } + return 0; +} + +static int +native_inop_read(struct inode *ino __IS_UNUSED, struct ioctx *ioctx) +{ + + return doio('r', ioctx); +} + +static int +native_inop_write(struct inode *ino __IS_UNUSED, struct ioctx *ioctx) +{ + + return doio('w', ioctx); +} + +static _SYSIO_OFF_T +native_inop_pos(struct inode *ino, _SYSIO_OFF_T off) +{ + struct native_inode *nino = I2NI(ino); + int err; + + err = native_pos(nino->ni_fd, &off, SEEK_SET); + return err < 0 ? err : off; +} + +static int +native_inop_iodone(struct ioctx *ioctxp __IS_UNUSED) +{ + + /* + * It's always done in this driver. It completed when posted. + */ + return 1; +} + +static int +native_inop_fcntl(struct inode *ino, + int cmd, + va_list ap) +{ + struct native_inode *nino = I2NI(ino); + long arg; + int err; + + if (nino->ni_fd < 0) + abort(); + + switch (cmd) { + case F_GETFD: + case F_GETFL: + case F_GETOWN: + err = syscall(SYS_fcntl, nino->ni_fd, cmd); + if (err < 0) + err = -errno; + case F_DUPFD: + case F_SETFD: + case F_SETFL: + case F_GETLK: + case F_SETLK: + case F_SETLKW: + case F_SETOWN: + arg = va_arg(ap, long); + err = syscall(SYS_fcntl, nino->ni_fd, cmd, arg); + if (err) + err = -errno; + default: + err = -EINVAL; + } + return err; +} + +static int +native_inop_mknod(struct pnode *pno __IS_UNUSED, + mode_t mode __IS_UNUSED, + dev_t dev __IS_UNUSED) +{ + + return -ENOSYS; +} + +#ifdef _HAVE_STATVFS +static int +native_inop_statvfs(struct pnode *pno, + struct inode *ino, + struct intnl_statvfs *buf) +{ + char *path; + int rc; + struct statfs fs; + + path = NULL; + if (!ino || I2NI(ino)->ni_fd < 0) { + path = _sysio_pb_path(pno->p_base, '/'); + if (!path) + return -ENOMEM; + } + + /* + * The syscall interface does not support SYS_fstatvfs. + * Should possibly return ENOSYS, but thought it + * better to use SYS_fstatfs and fill in as much of + * the statvfs structure as possible. This allows + * for more of a test of the sysio user interface. + */ + rc = + path + ? syscall(SYS_statfs, path, &fs) + : syscall(SYS_fstatfs, I2NI(ino)->ni_fd, &fs); + if (path) + free(path); + if (rc < 0) + return -errno; + + buf->f_bsize = fs.f_bsize; /* file system block size */ + buf->f_frsize = fs.f_bsize; /* file system fundamental block size */ + buf->f_blocks = fs.f_blocks; + buf->f_bfree = fs.f_bfree; + buf->f_bavail = fs.f_bavail; + buf->f_files = fs.f_files; /* Total number serial numbers */ + buf->f_ffree = fs.f_ffree; /* Number free serial numbers */ + buf->f_favail = fs.f_ffree; /* Number free ser num for non-privileged*/ + buf->f_fsid = fs.f_fsid.__val[1]; + buf->f_flag = 0; /* No equiv in statfs; maybe use type? */ + buf->f_namemax = fs.f_namelen; + return 0; +} +#endif + +static int +native_inop_sync(struct inode *ino) +{ + int err; + + assert(I2NI(ino)->ni_fd >= 0); + + err = syscall(SYS_fsync, I2NI(ino)->ni_fd); + if (err) + err = -errno; + return err; +} + +static int +native_inop_datasync(struct inode *ino) +{ + int err; + + assert(I2NI(ino)->ni_fd >= 0); + +#ifdef NATIVE_FDATASYNC + err = syscall(NATIVE_FDATASYNC, I2NI(ino)->ni_fd); +#else +#if 0 +#warning No fdatasync system call -- Using fsync instead! +#endif + err = syscall(SYS_fsync, I2NI(ino)->ni_fd); +#endif + if (err) + err = -errno; + return err; +} + +static int +native_inop_ioctl(struct inode *ino __IS_UNUSED, + unsigned long int request __IS_UNUSED, + va_list ap __IS_UNUSED) +{ + + /* + * I'm lazy. Maybe implemented later. + */ + errno = ENOTTY; + return -1; +} + +static void +native_inop_gone(struct inode *ino) +{ + struct native_inode *nino = I2NI(ino); + + if (nino->ni_fd >= 0) + (void )syscall(SYS_close, nino->ni_fd); + free(ino->i_private); +} + +static void +native_fsop_gone(struct filesys *fs __IS_UNUSED) +{ + + /* + * Do nothing. There is no private part maintained for the + * native file interface. + */ +} diff --git a/libsysio/drivers/native/fs_native.h b/libsysio/drivers/native/fs_native.h new file mode 100644 index 0000000..1590379 --- /dev/null +++ b/libsysio/drivers/native/fs_native.h @@ -0,0 +1,48 @@ +/* + * This Cplant(TM) source code is the property of Sandia National + * Laboratories. + * + * This Cplant(TM) source code is copyrighted by Sandia National + * Laboratories. + * + * The redistribution of this Cplant(TM) source code is subject to the + * terms of the GNU Lesser General Public License + * (see cit/LGPL or http://www.gnu.org/licenses/lgpl.html) + * + * Cplant(TM) Copyright 1998-2003 Sandia Corporation. + * Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive + * license for use of this work by or on behalf of the US Government. + * Export of this program may require a license from the United States + * Government. + */ + +/* + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Questions or comments about this library should be sent to: + * + * Lee Ward + * Sandia National Laboratories, New Mexico + * P.O. Box 5800 + * Albuquerque, NM 87185-1110 + * + * lee@sandia.gov + */ + +/* + * Native file system driver support. + */ + +extern int _sysio_native_init(void); diff --git a/libsysio/drivers/native/module.mk b/libsysio/drivers/native/module.mk new file mode 100644 index 0000000..8cada8a --- /dev/null +++ b/libsysio/drivers/native/module.mk @@ -0,0 +1,2 @@ +NATIVE_SRCS = drivers/native/fs_native.c +NATIVE_EXTRA = drivers/native/fs_native.h drivers/native/module.mk diff --git a/libsysio/drivers/sockets/module.mk b/libsysio/drivers/sockets/module.mk new file mode 100644 index 0000000..261fcfa --- /dev/null +++ b/libsysio/drivers/sockets/module.mk @@ -0,0 +1,2 @@ +SOCKETS_SRCS = drivers/sockets/sockets.c +SOCKETS_EXTRA = drivers/sockets/module.mk diff --git a/libsysio/drivers/sockets/sockets.c b/libsysio/drivers/sockets/sockets.c new file mode 100644 index 0000000..b8da195 --- /dev/null +++ b/libsysio/drivers/sockets/sockets.c @@ -0,0 +1,569 @@ +/* + * This Cplant(TM) source code is the property of Sandia National + * Laboratories. + * + * This Cplant(TM) source code is copyrighted by Sandia National + * Laboratories. + * + * The redistribution of this Cplant(TM) source code is subject to the + * terms of the GNU Lesser General Public License + * (see cit/LGPL or http://www.gnu.org/licenses/lgpl.html) + * + * Cplant(TM) Copyright 1998-2003 Sandia Corporation. + * Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive + * license for use of this work by or on behalf of the US Government. + * Export of this program may require a license from the United States + * Government. + */ + +/* + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Questions or comments about this library should be sent to: + * + * Lee Ward + * Sandia National Laboratories, New Mexico + * P.O. Box 5800 + * Albuquerque, NM 87185-1110 + * + * lee@sandia.gov + */ + +#ifdef __linux__ +#define _BSD_SOURCE +#endif + +#include /* for NULL */ +#include +#ifdef __linux__ +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "sysio.h" +#include "fs.h" +#include "inode.h" +#include "file.h" +#include "dev.h" /* _sysio_nodev_ops */ + +/* + * Sockets interface driver + */ + +/* + * Sockets file identifiers format. + */ +struct sockets_ino_identifier { + ino_t inum; /* i-number */ +}; + +/* + * Driver-private i-node information we keep about in-use sockets. + */ +struct socket_info { + struct sockets_ino_identifier ski_ident; /* unique identifier */ + struct file_identifier ski_fileid; /* ditto */ + int ski_fd; /* host fildes */ +}; + +static int sockets_inop_close(struct inode *ino); +static int sockets_inop_read(struct inode *ino, + struct ioctx *ioctx); +static int sockets_inop_write(struct inode *ino, + struct ioctx *ioctxp); +static _SYSIO_OFF_T sockets_inop_pos(struct inode *ino, + _SYSIO_OFF_T off); +static int sockets_inop_iodone(struct ioctx *ioctx); +static int sockets_inop_sync(struct inode *ino); +static int sockets_inop_datasync(struct inode *ino); +static int sockets_inop_fcntl(struct inode *ino, int cmd, va_list ap); +static int sockets_inop_ioctl(struct inode *ino, + unsigned long int request, + va_list ap); +static void sockets_inop_gone(struct inode *ino); +static void sockets_illop(void); + +/* + * Given i-node, return driver private part. + */ +#define I2SKI(ino) ((struct socket_info *)((ino)->i_private)) + +struct filesys_ops sockets_filesys_ops = { + (void (*)(struct filesys *))sockets_illop +}; + +static struct filesys *sockets_fs; + +static struct inode_ops sockets_i_ops; + +/* + * Initialize this driver. + */ +int +_sysio_sockets_init() +{ + + sockets_i_ops = _sysio_nodev_ops; + sockets_i_ops.inop_close = sockets_inop_close; + sockets_i_ops.inop_read = sockets_inop_read; + sockets_i_ops.inop_write = sockets_inop_write; + sockets_i_ops.inop_pos = sockets_inop_pos; + sockets_i_ops.inop_iodone = sockets_inop_iodone; + sockets_i_ops.inop_fcntl = sockets_inop_fcntl; + sockets_i_ops.inop_sync = sockets_inop_sync; + sockets_i_ops.inop_datasync = sockets_inop_datasync; + sockets_i_ops.inop_ioctl = sockets_inop_ioctl; + sockets_i_ops.inop_gone = sockets_inop_gone; + + sockets_fs = _sysio_fs_new(&sockets_filesys_ops, 0, NULL); + if (!sockets_fs) + return -ENOMEM; + + return 0; +} + +static int +sockets_inop_close(struct inode *ino) +{ + struct socket_info *ski = I2SKI(ino); + int err; + + if (ski->ski_fd < 0) + return -EBADF; + + err = syscall(SYS_close, ski->ski_fd); + if (err) + return -errno; + ski->ski_fd = -1; + return 0; +} + +/* + * A helper function performing the real IO operation work. + * + * We don't really have async IO. We'll just perform the function + * now. + */ +static int +doio(ssize_t (*f)(int, const struct iovec *, int), + struct inode *ino, + struct ioctx *ioctx) +{ + struct socket_info *ski = I2SKI(ino); + + assert(ski->ski_fd >= 0); + + /* XXX there's no way to check the position + * here we only could ingore the extends + */ + if (ioctx->ioctx_xtvlen != 1) + return -EINVAL; + + if (ioctx->ioctx_iovlen && (int) ioctx->ioctx_iovlen < 0) + return -EINVAL; + + /* + * Call the appropriate (read/write) IO function to + * transfer the data now. + */ + ioctx->ioctx_cc = + (*f)(ski->ski_fd, ioctx->ioctx_iov, ioctx->ioctx_iovlen); + if (ioctx->ioctx_cc < 0) + ioctx->ioctx_errno = errno; + + ioctx->ioctx_done = 1; + return 0; +} + +/* + * Helper function passed to doio(), above, to accomplish a real readv. + */ +static ssize_t +_readv(int fd, const struct iovec *vector, int count) +{ + + return syscall(SYS_readv, fd, vector, count); +} + +static int +sockets_inop_read(struct inode *ino, + struct ioctx *ioctx) +{ + + return doio(_readv, ino, ioctx); +} + +/* + * Helper function passed to doio(), above, to accomplish a real writev. + */ +static ssize_t +_writev(int fd, const struct iovec *vector, int count) +{ + + return syscall(SYS_writev, fd, vector, count); +} + +static int +sockets_inop_write(struct inode *ino, + struct ioctx *ioctx) +{ + + return doio(_writev, ino, ioctx); +} + +static _SYSIO_OFF_T +sockets_inop_pos(struct inode *ino, _SYSIO_OFF_T off) +{ + return -EINVAL; +} + +static int +sockets_inop_iodone(struct ioctx *ioctxp __IS_UNUSED) +{ + + /* + * It's always done in this driver. It completed when posted. + */ + return 1; +} + +static int +sockets_inop_fcntl(struct inode *ino __IS_UNUSED, + int cmd __IS_UNUSED, + va_list ap __IS_UNUSED) +{ + long arg; + + assert(I2SKI(ino)->ski_fd >= 0); + + switch (cmd) { + case F_GETFD: + case F_GETFL: + case F_GETOWN: + return syscall(SYS_fcntl, I2SKI(ino)->ski_fd, cmd); + case F_DUPFD: + case F_SETFD: + case F_SETFL: + case F_GETLK: + case F_SETLK: + case F_SETLKW: + case F_SETOWN: + arg = va_arg(ap, long); + return syscall(SYS_fcntl, I2SKI(ino)->ski_fd, cmd, arg); + default: + printf("uncatched cmd %d\n", cmd); + abort(); + } + return -1; +} + +static int +sockets_inop_sync(struct inode *ino) +{ + + assert(I2SKI(ino)->ski_fd >= 0); + + return syscall(SYS_fsync, I2SKI(ino)->ski_fd); +} + +static int +sockets_inop_datasync(struct inode *ino) +{ + + assert(I2SKI(ino)->ski_fd >= 0); + + return syscall(SYS_fdatasync, I2SKI(ino)->ski_fd); +} + +static int +sockets_inop_ioctl(struct inode *ino __IS_UNUSED, + unsigned long int request __IS_UNUSED, + va_list ap __IS_UNUSED) +{ + /* + * I'm lazy. Maybe implemented later. + */ + return -ENOTTY; +} + +static void +sockets_inop_gone(struct inode *ino) +{ + + (void )sockets_inop_close(ino); + free(ino->i_private); +} + +static void +sockets_illop(void) +{ + + abort(); +} + +static struct inode * +_sysio_sockets_inew() +{ + static ino_t inum = 1; + struct socket_info *ski; + struct inode *ino; + + ski = malloc(sizeof(struct socket_info)); + if (!ski) + return NULL; + ski->ski_ident.inum = inum++; + ski->ski_fileid.fid_data = &ski->ski_ident; + ski->ski_fileid.fid_len = sizeof(ski->ski_ident); + ski->ski_fd = -1; + + ino = + _sysio_i_new(sockets_fs, + &ski->ski_fileid, + 0, + 0, + 0, + &sockets_i_ops, + ski); + if (!ino) + free(ski); + + return ino; +} + +int +socket(int domain, int type, int protocol) +{ + int err; + struct inode *ino; + struct socket_info *ski; + struct file *fil; + + err = 0; + fil = NULL; + + ino = _sysio_sockets_inew(); + if (!ino) { + err = -ENOMEM; + goto error; + } + + ski = I2SKI(ino); +#ifndef SYS_socketcall + ski->ski_fd = syscall(SYS_socket, domain, type, protocol); +#else + { + unsigned long avec[3] = {domain, type, protocol}; + ski->ski_fd = syscall(SYS_socketcall, SYS_SOCKET, avec); + } +#endif + if (ski->ski_fd < 0) { + err = -errno; + goto error; + } + + fil = _sysio_fnew(ino, O_RDWR); + if (!fil) { + err = -ENOMEM; + goto error; + } + + err = _sysio_fd_set(fil, ski->ski_fd); + if (err < 0) + goto error; + + return err; + +error: + if (fil) + F_RELE(fil); + if (ino) + I_RELE(ino); + + errno = -err; + return -1; +} + +int +accept(int s, struct sockaddr *addr, socklen_t *addrlen) +{ + int err; + struct inode *ino; + struct socket_info *ski; + struct file *ofil, *nfil; + + err = 0; + nfil = NULL; + ino = NULL; + + ofil = _sysio_fd_find(s); + if (!ofil) { + err = -EBADF; + goto error; + } + + ino = _sysio_sockets_inew(); + if (!ino) { + err = -ENOMEM; + goto error; + } + + nfil = _sysio_fnew(ino, O_RDWR); + if (!nfil) { + err = -ENOMEM; + goto error; + } + + ski = I2SKI(ino); +#ifndef SYS_socketcall + ski->ski_fd = syscall(SYS_accept, I2SKI(ofil->f_ino)->ski_fd, + addr, addrlen); +#else + { + unsigned long avec[3] = { + (unsigned long) I2SKI(ofil->f_ino)->ski_fd, + (unsigned long) addr, + (unsigned long) addrlen}; + ski->ski_fd = syscall(SYS_socketcall, SYS_ACCEPT, avec); + } +#endif + if (ski->ski_fd < 0) { + err = -errno; + goto error; + } + + err = _sysio_fd_set(nfil, ski->ski_fd); + if (err < 0) + goto error; + + return err; + +error: + if (nfil) + F_RELE(nfil); + if (ino) + I_RELE(ino); + + errno = -err; + return -1; +} + +int +bind(int sockfd, const struct sockaddr *my_addr, socklen_t addrlen) +{ + int err; + struct file *fil; + unsigned long avec[3]; + + err = 0; + + fil = _sysio_fd_find(sockfd); + if (!fil) { + err = -EBADF; + goto out; + } + +#ifndef SYS_socketcall + if (syscall(SYS_bind, I2SKI(fil->f_ino)->ski_fd, my_addr, addrlen)) { +#else + avec[0] = I2SKI(fil->f_ino)->ski_fd; + avec[1] = (unsigned long )my_addr; + avec[2] = addrlen; + if (syscall(SYS_socketcall, SYS_BIND, avec) != 0) { +#endif + err = -errno; + goto out; + } + + return 0; +out: + errno = -err; + return -1; +} + +int +listen(int s, int backlog) +{ + int err; + struct file *fil; + unsigned long avec[2]; + + err = 0; + + fil = _sysio_fd_find(s); + if (!fil) { + err = -EBADF; + goto out; + } + +#ifndef SYS_socketcall + if (syscall(SYS_listen, I2SKI(fil->f_ino)->ski_fd, backlog) != 0) { +#else + avec[0] = I2SKI(fil->f_ino)->ski_fd; + avec[1] = backlog; + if (syscall(SYS_socketcall, SYS_LISTEN, avec) != 0) { +#endif + err = -errno; + goto out; + } + + return 0; +out: + errno = -err; + return -1; +} + +int +connect(int sockfd, const struct sockaddr *serv_addr, socklen_t addrlen) +{ + int err; + struct file *fil; + unsigned long avec[3]; + + err = 0; + + fil = _sysio_fd_find(sockfd); + if (!fil) { + err = -EBADF; + goto out; + } + +#ifndef SYS_socketcall + if (syscall(SYS_connect, I2SKI(fil->f_ino)->ski_fd, + serv_addr, addrlen) != 0) { +#else + avec[0] = I2SKI(fil->f_ino)->ski_fd; + avec[1] = (unsigned long )serv_addr; + avec[2] = addrlen; + if (syscall(SYS_socketcall, SYS_CONNECT, avec) != 0) { +#endif + err = -errno; + goto out; + } + + return 0; +out: + errno = -err; + return -1; +} diff --git a/libsysio/drivers/yod/fs_yod.c b/libsysio/drivers/yod/fs_yod.c new file mode 100644 index 0000000..d651b88 --- /dev/null +++ b/libsysio/drivers/yod/fs_yod.c @@ -0,0 +1,1224 @@ +/* + * This Cplant(TM) source code is the property of Sandia National + * Laboratories. + * + * This Cplant(TM) source code is copyrighted by Sandia National + * Laboratories. + * + * The redistribution of this Cplant(TM) source code is subject to the + * terms of the GNU Lesser General Public License + * (see cit/LGPL or http://www.gnu.org/licenses/lgpl.html) + * + * Cplant(TM) Copyright 1998-2003 Sandia Corporation. + * Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive + * license for use of this work by or on behalf of the US Government. + * Export of this program may require a license from the United States + * Government. + */ + +/* + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Questions or comments about this library should be sent to: + * + * Lee Ward + * Sandia National Laboratories, New Mexico + * P.O. Box 5800 + * Albuquerque, NM 87185-1110 + * + * lee@sandia.gov + */ + +#ifdef __linux__ +#define _BSD_SOURCE +#endif + +#include /* for NULL */ +#include +#ifdef __linux__ +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#if 0 +#include +#endif +#ifdef _HAVE_STATVFS +#include +#endif +#include +#include +#include + +#include "sysio.h" +#include "fs.h" +#include "mount.h" +#include "inode.h" + +#include "fs_yod.h" + +/* + * Remote file system driver + * calls are re-directed to the initiating yod + */ +#include "cplant-yod.h" + +/* stat struct used by yod, which + * is not compiled with __USE_FILE_OFFSET64 + */ +#define __yod_stat stat +#ifdef ALPHA_LINUX +#define COPY_STAT(src, dest) \ +do { \ + memset((dest), 0, sizeof((*dest))); \ + (dest)->st_dev = (src)->st_dev; \ + (dest)->st_ino = (src)->st_ino; \ + (dest)->st_mode = (src)->st_mode; \ + (dest)->st_nlink = (src)->st_nlink; \ + (dest)->st_uid = (src)->st_uid; \ + (dest)->st_gid = (src)->st_gid; \ + (dest)->st_rdev = (src)->st_rdev; \ + (dest)->st_size = (src)->st_size; \ + (dest)->st_atime = (src)->st_atime; \ + (dest)->st_mtime = (src)->st_mtime; \ + (dest)->st_ctime = (src)->st_ctime; \ + (dest)->st_blksize = (src)->st_blksize; \ + (dest)->st_blocks = (src)->st_blocks; \ + (dest)->st_flags = (src)->st_flags; \ + (dest)->st_gen = (src)->st_gen; \ +} while (0); +#else +#define COPY_STAT(src, dest) \ +do { \ + memset((dest), 0, sizeof((*dest))); \ + (dest)->st_dev = (src)->st_dev; \ + (dest)->st_ino = (src)->st_ino; \ + (dest)->st_mode = (src)->st_mode; \ + (dest)->st_nlink = (src)->st_nlink; \ + (dest)->st_uid = (src)->st_uid; \ + (dest)->st_gid = (src)->st_gid; \ + (dest)->st_rdev = (src)->st_rdev; \ + (dest)->st_size = (src)->st_size; \ + (dest)->st_atime = (src)->st_atime; \ + (dest)->st_mtime = (src)->st_mtime; \ + (dest)->st_ctime = (src)->st_ctime; \ + (dest)->st_blksize = (src)->st_blksize; \ + (dest)->st_blocks = (src)->st_blocks; \ +} while (0); +#endif + +/* + * Yod file identifiers format. + */ +struct yod_inode_identifier { + dev_t dev; /* device number */ + ino_t ino; /* i-number */ +#ifdef HAVE_GENERATION + unsigned int gen; /* generation number */ +#endif +}; + +/* + * Driver-private i-node information we keep about local host file + * system objects. + */ +struct yod_inode { + unsigned ni_seekok : 1; /* can seek? */ + struct yod_inode_identifier ni_ident; /* unique identifier */ + struct file_identifier ni_fileid; /* ditto */ + int ni_fd; /* host fildes */ + int ni_oflags; /* flags, from open */ + unsigned ni_nopens; /* soft ref count */ + _SYSIO_OFF_T ni_fpos; /* current pos */ +}; + +static int yod_inop_lookup(struct pnode *pno, + struct inode **inop, + struct intent *intnt, + const char *path); +static int yod_inop_getattr(struct pnode *pno, + struct inode *ino, + struct intnl_stat *stbuf); +static int yod_inop_setattr(struct pnode *pno, + struct inode *ino, + unsigned mask, + struct intnl_stat *stbuf); +static ssize_t yod_getdirentries(struct inode *ino, + char *buf, + size_t nbytes, + off64_t *basep); +static int yod_inop_mkdir(struct pnode *pno, mode_t mode); +static int yod_inop_rmdir(struct pnode *pno); +static int yod_inop_symlink(struct pnode *pno, const char *data); +static int yod_inop_readlink(struct pnode *pno, char *buf, size_t bufsiz); +static int yod_inop_open(struct pnode *pno, int flags, mode_t mode); +static int yod_inop_close(struct inode *ino); +static int yod_inop_link(struct pnode *old, struct pnode *new); +static int yod_inop_unlink(struct pnode *pno); +static int yod_inop_rename(struct pnode *old, struct pnode *new); +static _SYSIO_OFF_T yod_inop_pos (struct inode *ino, _SYSIO_OFF_T off); +static int yod_inop_read(struct inode *ino, struct ioctx *ioctx); +static int yod_inop_write(struct inode *ino, struct ioctx *ioctx); +static int yod_inop_iodone(struct ioctx *ioctx); +static int yod_inop_fcntl(struct inode *ino, int cmd, va_list ap); +static int yod_inop_sync(struct inode *ino); +static int yod_inop_datasync(struct inode *ino); +static int yod_inop_ioctl(struct inode *ino, + unsigned long int request, + va_list ap); +static int yod_inop_mknod(struct pnode *pno, mode_t mode, dev_t dev); +#ifdef _HAVE_STATVFS +static int yod_inop_statvfs(struct pnode *pno, + struct inode *ino, + struct intnl_statvfs *buf); +#endif +static void yod_inop_gone(struct inode *ino); + +static struct inode_ops yod_i_ops = { + yod_inop_lookup, + yod_inop_getattr, + yod_inop_setattr, + yod_getdirentries, + yod_inop_mkdir, + yod_inop_rmdir, + yod_inop_symlink, + yod_inop_readlink, + yod_inop_open, + yod_inop_close, + yod_inop_link, + yod_inop_unlink, + yod_inop_rename, + yod_inop_read, + yod_inop_write, + yod_inop_pos, + yod_inop_iodone, + yod_inop_fcntl, + yod_inop_sync, + yod_inop_datasync, + yod_inop_ioctl, + yod_inop_mknod, +#ifdef _HAVE_STATVFS + yod_inop_statvfs, +#endif + yod_inop_gone +}; + +static int yod_fsswop_mount(const char *source, + unsigned flags, + const void *data, + struct pnode *tocover, + struct mount **mntp); + +static struct fssw_ops yod_fssw_ops = { + yod_fsswop_mount +}; + +static void yod_fsop_gone(struct filesys *fs); + +static struct filesys_ops yod_inodesys_ops = { + yod_fsop_gone +}; + +/* + * Placeholder internal mount as in native driver + */ +static struct mount *yod_internal_mount = NULL; + +/* + * Given i-node, return driver private part. + */ +#define I2NI(ino) ((struct yod_inode *)((ino)->i_private)) + +/* + * stat -- by path. + */ +static int +yod_stat(const char *path, struct intnl_stat *buf) +{ + int err; + struct __yod_stat stbuf; + + err = stat_yod(path, &stbuf); + if (err) + err = -errno; + COPY_STAT(&stbuf, buf); + + return err; +} + +/* + * stat -- by fildes + */ +static int +yod_fstat(int fd, struct intnl_stat *buf) +{ + int err; + struct __yod_stat stbuf; + + err = fstat_yod(fd, &stbuf); + if (err) + err = -errno; + COPY_STAT(&stbuf, buf); + + return err; +} + +/* + * Introduce an i-node to the system. + */ +static struct inode * +yod_i_new(struct filesys *fs, struct intnl_stat *buf) +{ + struct yod_inode *nino; + struct inode *ino; + + nino = malloc(sizeof(struct yod_inode)); + if (!nino) + return NULL; + bzero(&nino->ni_ident, sizeof(nino->ni_ident)); + nino->ni_ident.dev = buf->st_dev; + nino->ni_ident.ino = buf->st_ino; +#ifdef HAVE_GENERATION + nino->ni_ident.gen = buf->st_gen; +#endif + nino->ni_fileid.fid_data = &nino->ni_ident; + nino->ni_fileid.fid_len = sizeof(nino->ni_ident); + nino->ni_fd = -1; + nino->ni_oflags = 0; + nino->ni_nopens = 0; + nino->ni_fpos = 0; + ino = + _sysio_i_new(fs, + &nino->ni_fileid, +#ifndef AUTOMOUNT_FILE_NAME + buf->st_mode & S_IFMT, +#else + buf->st_mode, /* all of the bits! */ +#endif + 0, + 0, + &yod_i_ops, + nino); + if (!ino) + free(nino); + return ino; +} + +/* + * Initialize this driver. + */ +int +_sysio_yod_init() +{ + + /* + * Capture current process umask and reset our process umask to + * zero. All permission bits to open/creat/setattr are absolute -- + * They've already had a umask applied, when appropriate. + */ + _sysio_umask = syscall(SYS_umask, 0); + + return _sysio_fssw_register("yod", &yod_fssw_ops); +} + +/* + * Create private, internal, view of the hosts name space. + */ +static int +create_internal_namespace() +{ + int err; + struct mount *mnt; + struct inode *rootino; + struct pnode_base *rootpb; + static struct qstr noname = { NULL, 0, 0 }; + struct filesys *fs; + struct intnl_stat stbuf; + + if (yod_internal_mount) { + /* + * Reentered! + */ + abort(); + } + + /* + * We maintain an artificial, internal, name space in order to + * have access to fully qualified path names in the various routines. + * Initialize that name space now. + */ + mnt = NULL; + rootino = NULL; + rootpb = NULL; + fs = _sysio_fs_new(&yod_inodesys_ops, 0, NULL); + if (!fs) { + err = -ENOMEM; + goto error; + } + + /* + * Get root i-node. + */ + err = yod_stat("/", &stbuf); + if (err) + goto error; + rootino = yod_i_new(fs, &stbuf); + if (!rootino) { + err = -ENOMEM; + goto error; + } + + /* + * Generate base path-node for root. + */ + rootpb = _sysio_pb_new(&noname, NULL, rootino); + if (!rootpb) { + err = -ENOMEM; + goto error; + } + + /* + * Mount it. This name space is disconnected from the + * rest of the system -- Only available within this driver. + */ + err = _sysio_do_mount(fs, rootpb, 0, NULL, &mnt); + if (err) + goto error; + + yod_internal_mount = mnt; + return 0; +error: + if (mnt) { + if (_sysio_do_unmount(mnt) != 0) + abort(); + fs = NULL; + rootpb = NULL; + rootino = NULL; + } + if (rootpb) + _sysio_pb_gone(rootpb); + if (fs) { + FS_RELE(fs); + _sysio_fs_gone(fs); + } + + return err; +} + +static int +yod_fsswop_mount(const char *source, + unsigned flags, + const void *data __IS_UNUSED, + struct pnode *tocover, + struct mount **mntp) +{ + int err; + struct nameidata nameidata; + struct mount *mnt; + + /* + * Caller must use fully qualified path names when specifying + * the source. + */ + if (*source != '/') + return -ENOENT; + + if (!yod_internal_mount) { + err = create_internal_namespace(); + if (err) + return err; + } + + /* + * Lookup the source in the internally maintained name space. + */ + ND_INIT(&nameidata, 0, source, yod_internal_mount->mnt_root, NULL); + err = _sysio_path_walk(yod_internal_mount->mnt_root, &nameidata); + if (err) + return err; + + /* + * Have path-node specified by the given source argument. Let the + * system finish the job, now. + */ + err = + _sysio_do_mount(yod_internal_mount->mnt_fs, + nameidata.nd_pno->p_base, + flags, + tocover, + &mnt); + /* + * Release the internal name space pnode and clean up any + * aliases we might have generated. We really don't need to cache them + * as they are only used at mount time.. + */ + P_RELE(nameidata.nd_pno); + (void )_sysio_p_prune(yod_internal_mount->mnt_root); + + if (!err) { + FS_REF(yod_internal_mount->mnt_fs); + *mntp = mnt; + } + return err; +} + +static int +yod_i_invalid(struct inode *inop, struct intnl_stat stbuf) +{ + /* + * Validate passed in inode against stat struct info + */ + struct yod_inode *nino = I2NI(inop); + + if ((nino->ni_ident.dev != stbuf.st_dev || + nino->ni_ident.ino != stbuf.st_ino || +#ifdef HAVE_GENERATION + nino->ni_ident.gen != stbuf.st_gen || +#endif + ((inop)->i_mode & S_IFMT) != (stbuf.st_mode & S_IFMT)) || + (((inop)->i_rdev != stbuf.st_rdev) && + (S_ISCHR((inop)->i_mode) || S_ISBLK((inop)->i_mode)))) + return 1; + + return 0; +} + +/* + * Find, and validate, or create i-node by host-relative path. Returned i-node + * is referenced. + */ +static int +yod_iget(struct filesys *fs, + const char *path, + struct inode **inop, + int forced) +{ + int err; + struct inode *ino; + struct intnl_stat stbuf; + struct yod_inode_identifier ident; + struct file_identifier fileid; + + /* + * Get file status. + */ + err = yod_stat(path, &stbuf); + if (err) { + *inop = NULL; + return err; + } + + /* + * Validate? + */ + if (*inop) { + if (!yod_i_invalid(*inop, stbuf)) + return 0; + /* + * Invalidate. + */ + *inop = NULL; + } + + /* + * I-node is not already known. Find or create it. + */ + bzero(&ident, sizeof(ident)); + ident.dev = stbuf.st_dev; + ident.ino = stbuf.st_ino; +#ifdef HAVE_GENERATION + ident.gen = stbuf.st_gen; +#endif + fileid.fid_data = &ident; + fileid.fid_len = sizeof(ident); + ino = _sysio_i_find(fs, &fileid); + if (ino && forced) { + /* + * Insertion was forced but it's already present! + */ + if (yod_i_invalid(ino, stbuf)) { + /* + * Cached inode has stale attrs + * make way for the new one + */ + I_RELE(ino); + _sysio_i_undead(ino); + ino = NULL; + } else + /* + * OK to reuse cached inode + */ + goto out; + } + + if (!ino) { + ino = yod_i_new(fs, &stbuf); + if (!ino) + err = -ENOMEM; + } +out: + if (!err) + *inop = ino; + return err; +} + +/* + * Look up named object in host's name space by path. + */ +static int +yod_path_lookup(struct filesys *fs, const char *path, struct inode **inop) +{ + + return yod_iget(fs, path, inop, 0); +} + +/* + * Look up object by it's path node. + */ +static int +yod_i_lookup(struct filesys *fs, struct pnode_base *pb, struct inode **inop) +{ + int err; + char *path; + + path = _sysio_pb_path(pb, '/'); + if (!path) + return -ENOMEM; + err = yod_path_lookup(fs, path, inop); + free(path); + return err; +} + +static int +yod_inop_lookup(struct pnode *pno, + struct inode **inop, + struct intent *intnt __IS_UNUSED, + const char *path __IS_UNUSED) +{ + int err; + + *inop = pno->p_base->pb_ino; + + /* + * Don't have an inode yet. Because we translate everything back to + * a single name space for the host, we will assume the object the + * caller is looking for has no existing alias in our internal + * name space. We don't see the same file on different mounts in the + * underlying host FS as the same file. + * + * The file identifier *will* be unique. It's got to have a different + * dev. + */ + err = yod_i_lookup(pno->p_mount->mnt_fs, pno->p_base, inop); + if (err) + *inop = NULL; + return err; +} + +static int +yod_inop_getattr(struct pnode *pno, struct inode *ino, struct intnl_stat *stbuf) +{ + char *path; + int err; + + path = NULL; + if (!ino || I2NI(ino)->ni_fd < 0) { + path = _sysio_pb_path(pno->p_base, '/'); + if (!path) + return -ENOMEM; + } + err = + path + ? yod_stat(path, stbuf) + : yod_fstat(I2NI(ino)->ni_fd, stbuf); + if (path) + free(path); + return err; +} + +static int +yod_inop_setattr(struct pnode *pno, + struct inode *ino, + unsigned mask, + struct intnl_stat *stbuf) +{ + char *path; + int fd; + struct intnl_stat st; + int err; + + path = NULL; + fd = ino ? I2NI(ino)->ni_fd : -1; + if (fd < 0 || mask & (SETATTR_MTIME|SETATTR_ATIME)) { + if (!pno) + return -EEXIST; + path = _sysio_pb_path(pno->p_base, '/'); + if (!path) + return -ENOMEM; + } + + /* + * Get current status for undo. + */ + err = + fd < 0 + ? yod_stat(path, &st) + : yod_fstat(fd, &st); + if (err) + goto out; + + if (mask & SETATTR_MODE) { + mode_t mode; + + /* + * Alter permissions attribute. + */ + mode = stbuf->st_mode & 07777; + err = chmod_yod(path, mode); + } + if (err) + mask &= ~SETATTR_MODE; + + if (mask & (SETATTR_UID|SETATTR_GID)) { + + /* + * Alter owner and/or group identifiers. + */ + err = chown_yod(path, + mask & SETATTR_UID + ? stbuf->st_uid + : (uid_t )-1, + mask & SETATTR_GID + ? stbuf->st_gid + : (gid_t )-1); + } + if (err) + mask &= ~(SETATTR_UID|SETATTR_GID); + else if (mask & SETATTR_LEN) { + /* + * Do the truncate last. It can't be undone. + */ + (void )(fd < 0 + ? truncate_yod(path, stbuf->st_size) + : ftruncate_yod(fd, stbuf->st_size)); + } + if (!err) + goto out; + /* + * Undo after error. Some or all of this might not work... We + * can but try. + */ + if (mask & (SETATTR_UID|SETATTR_GID)) { + (void )chown_yod(path, + mask & SETATTR_UID + ? st.st_uid + : (uid_t )-1, + mask & SETATTR_GID + ? st.st_gid + : (gid_t )-1); + } + if (mask & SETATTR_MODE) { + chmod_yod(path, st.st_mode & 07777); + } +out: + if (path) + free(path); + return err; +} + +static ssize_t +yod_getdirentries(struct inode *ino, + char *buf, + size_t nbytes, + off64_t *basep) +{ + struct yod_inode *nino = I2NI(ino); + loff_t result; + ssize_t cc; + + assert(nino->ni_fd >= 0); + + result = *basep; + if (*basep != nino->ni_fpos && + (result = lseek_yod(nino->ni_fd, + *basep, + SEEK_SET) == -1)) + return -errno; + nino->ni_fpos = result; + cc = getdirentries_yod(nino->ni_fd, buf, nbytes, &result); + if (cc < 0) + return -errno; + nino->ni_fpos += cc; + return cc; +} + +static int +yod_inop_mkdir(struct pnode *pno, mode_t mode) +{ + char *path; + int err; + + path = _sysio_pb_path(pno->p_base, '/'); + if (!path) + return -ENOMEM; + + err = mkdir_yod(path, mode); + free(path); + return err; +} + +static int +yod_inop_rmdir(struct pnode *pno) +{ + char *path; + int err; + + path = _sysio_pb_path(pno->p_base, '/'); + if (!path) + return -ENOMEM; + + err = rmdir_yod(path); + free(path); + return err; +} + +static int +yod_inop_symlink(struct pnode *pno, const char *data) +{ + char *path; + int err; + + path = _sysio_pb_path(pno->p_base, '/'); + if (!path) + return -ENOMEM; + + err = symlink_yod(data, path); + free(path); + return err; +} + +static int +yod_inop_readlink(struct pnode *pno __IS_UNUSED, + char *buf __IS_UNUSED, + size_t bufsiz __IS_UNUSED) +{ + + return -ENOSYS; +} + +static int +yod_inop_open(struct pnode *pno, int flags, mode_t mode) +{ + struct yod_inode *nino; + char *path; + int fd; + + path = _sysio_pb_path(pno->p_base, '/'); + if (!path) + return -ENOMEM; + + /* + * Whether the file is already open, or not, makes no difference. + * Want to always give the host OS a chance to authorize in case + * something has changed underneath us. + */ + if (flags & O_WRONLY) { + /* + * Promote write-only attempt to RW. + */ + flags &= ~O_WRONLY; + flags |= O_RDWR; + } + fd = open_yod(path, flags, mode); + if (!pno->p_base->pb_ino && fd >= 0) { + int err; + + /* + * Success but we need to return an i-node. + */ + err = + yod_iget(pno->p_mount->mnt_fs, + path, + &pno->p_base->pb_ino, + 1); + if (err) { + (void )close_yod(fd); + if (err == -EEXIST) + abort(); + fd = err; + } + } + free(path); + if (fd < 0) + return -errno; + + /* + * Remember this new open. + */ + nino = I2NI(pno->p_base->pb_ino); + nino->ni_nopens++; + assert(nino->ni_nopens); + + if (nino->ni_fd >= 0) { + if ((nino->ni_oflags & O_RDWR) || + (flags & (O_RDONLY|O_WRONLY|O_RDWR)) == O_RDONLY) { + /* + * Keep existing. + */ + (void )close_yod(fd); + return 0; + } + (void )close_yod(nino->ni_fd); + } + /* + * Invariant; First open. Must init. + */ + nino->ni_fpos = 0; + nino->ni_fd = fd; + + /* + * Need to know whether we can seek on this + * descriptor. + */ + nino->ni_seekok = + lseek_yod(nino->ni_fd, 0, SEEK_CUR) != 0 ? 0 : 1; + + return 0; +} + +static int +yod_inop_close(struct inode *ino) +{ + struct yod_inode *nino = I2NI(ino); + int err; + + if (nino->ni_fd < 0) + abort(); + + assert(nino->ni_nopens); + if (--nino->ni_nopens) + return 0; + + err = close_yod(nino->ni_fd); + if (err) + return -errno; + + nino->ni_fd = -1; + nino->ni_fpos = 0; + return 0; +} + +static int +yod_inop_link(struct pnode *old, struct pnode *new) +{ + int err; + char *opath, *npath; + + err = 0; + + opath = _sysio_pb_path(old->p_base, '/'); + npath = _sysio_pb_path(new->p_base, '/'); + if (!(opath && npath)) { + err = -ENOMEM; + goto out; + } + + err = link_yod(opath, npath); + +out: + if (opath) + free(opath); + if (npath) + free(npath); + + return err; +} + +static int +yod_inop_unlink(struct pnode *pno) +{ + char *path; + int err = 0; + + path = _sysio_pb_path(pno->p_base, '/'); + if (!path) + return -ENOMEM; + + /* + * For this driver, unlink is easy with open files. Since the + * file remains open to the system, too, the descriptors are still + * valid. + * + * Other drivers will have some difficulty here as the entry in the + * file system name space must be removed without sacrificing access + * to the file itself. In NFS this is done with a mechanism referred + * to as a `silly delete'. The file is moved to a temporary name + * (usually .NFSXXXXXX, where the X's are replaced by the PID and some + * unique characters) in order to simulate the proper semantic. + */ + if (unlink_yod(path) != 0) + err = -errno; + free(path); + return err; +} + +/* + * A helper function performing the real IO operation work. + * + * We don't really have async IO. We'll just perform the function + * now. + */ +static int +doio(ssize_t (*f)(void *, size_t, _SYSIO_OFF_T, struct yod_inode *), + struct ioctx *ioctx) +{ + struct yod_inode *nino = I2NI(ioctx->ioctx_ino); + + ioctx->ioctx_cc = + _sysio_doio(ioctx->ioctx_xtv, ioctx->ioctx_xtvlen, + ioctx->ioctx_iov, ioctx->ioctx_iovlen, + (ssize_t (*)(void *, size_t, + _SYSIO_OFF_T, void *))f, + nino); + if (ioctx->ioctx_cc < 0) { + ioctx->ioctx_errno = -ioctx->ioctx_cc; + ioctx->ioctx_cc = -1; + return -1; + } + nino->ni_fpos += ioctx->ioctx_cc; + ioctx->ioctx_done = 1; + return 0; +} + +static ssize_t +yod_read_simple(void *buf, + size_t nbytes, + _SYSIO_OFF_T off, + struct yod_inode *nino) +{ + if (off != nino->ni_fpos) { + _SYSIO_OFF_T rtn; + + rtn = lseek_yod(nino->ni_fd, off, SEEK_SET); + if (rtn < 0) + return -1; + nino->ni_fpos = rtn; + } + return read_yod(nino->ni_fd, buf, nbytes); +} + +static int +yod_inop_read(struct inode *ino __IS_UNUSED, struct ioctx *ioctx) +{ + + return doio(yod_read_simple, ioctx); +} + +static int +yod_inop_rename(struct pnode *old, struct pnode *new) +{ + int err; + char *opath, *npath; + + opath = _sysio_pb_path(old->p_base, '/'); + npath = _sysio_pb_path(new->p_base, '/'); + if (!(opath && npath)) { + err = -ENOMEM; + goto out; + } + + err = rename_yod(opath, npath); + +out: + if (opath) + free(opath); + if (npath) + free(npath); + + return err; +} + +static ssize_t +yod_write_simple(void *buf, + size_t nbytes, + _SYSIO_OFF_T off, + struct yod_inode *nino) +{ + + if (off != nino->ni_fpos) { + _SYSIO_OFF_T rtn; + + rtn = lseek_yod(nino->ni_fd, off, SEEK_SET); + if (rtn < 0) + return -1; + nino->ni_fpos = rtn; + } + return write_yod(nino->ni_fd, buf, nbytes); +} + +static int +yod_inop_write(struct inode *ino __IS_UNUSED, struct ioctx *ioctx) +{ + + return doio(yod_write_simple, ioctx); +} + +static _SYSIO_OFF_T +yod_inop_pos(struct inode *ino, _SYSIO_OFF_T off) +{ + struct yod_inode *nino = I2NI(ino); + int err; + + err = lseek_yod(nino->ni_fd, off, SEEK_SET); + return err < 0 ? err : off; +} + +static int +yod_inop_iodone(struct ioctx *ioctxp __IS_UNUSED) +{ + + /* + * It's always done in this driver. It completed when posted. + */ + return 1; +} + +static int +yod_inop_fcntl(struct inode *ino __IS_UNUSED, int cmd, va_list ap __IS_UNUSED) +{ + switch (cmd) + { + case F_DUPFD: /* do something to the ino */ + break; + default: + errno = EINVAL; + return -1; + } + return 0; + +} + +static int +yod_inop_mknod(struct pnode *pno __IS_UNUSED, + mode_t mode __IS_UNUSED, + dev_t dev __IS_UNUSED) +{ + + return -ENOSYS; +} + +#ifdef _HAVE_STATVFS +static int +yod_inop_statvfs(struct pnode *pno, + struct inode *ino, + struct intnl_statvfs *buf) +{ + char *path; + int rc; + struct statfs fs; + + path = NULL; + if (!ino || I2NI(ino)->ni_fd < 0) { + path = _sysio_pb_path(pno->p_base, '/'); + if (!path) + return -ENOMEM; + } + + /* + * The syscall interface does not support SYS_fstatvfs. + * Should possibly return ENOSYS, but thought it + * better to use SYS_fstatfs and fill in as much of + * the statvfs structure as possible. This allows + * for more of a test of the sysio user interface. + */ + rc = + path + ? statfs_yod(path, &fs) + : fstatfs_yod(I2NI(ino)->ni_fd, &fs); + if (path) + free(path); + if (rc < 0) + return -errno; + + buf->f_bsize = fs.f_bsize; /* file system block size */ + buf->f_frsize = fs.f_bsize; /* file system fundamental block size */ + buf->f_blocks = fs.f_blocks; + buf->f_bfree = fs.f_bfree; + buf->f_bavail = fs.f_bavail; + buf->f_files = fs.f_files; /* Total number serial numbers */ + buf->f_ffree = fs.f_ffree; /* Number free serial numbers */ + buf->f_favail = fs.f_ffree; /* Number free ser num for non-privileged*/ + buf->f_fsid = fs.f_fsid.__val[1]; + buf->f_flag = 0; /* No equiv in statfs; maybe use type? */ + buf->f_namemax = fs.f_namelen; + return 0; +} +#endif + +static int +yod_inop_sync(struct inode *ino) +{ + + assert(I2NI(ino)->ni_fd >= 0); + + return fsync_yod(I2NI(ino)->ni_fd); +} + +static int +yod_inop_datasync(struct inode *ino) +{ + + assert(I2NI(ino)->ni_fd >= 0); + + return fsync_yod(I2NI(ino)->ni_fd); +} + +static int +yod_inop_ioctl(struct inode *ino __IS_UNUSED, + unsigned long int request __IS_UNUSED, + va_list ap __IS_UNUSED) +{ + + /* + * I'm lazy. Maybe implemented later. + */ + errno = ENOTTY; + return -1; +} + +static void +yod_inop_gone(struct inode *ino) +{ + struct yod_inode *nino = I2NI(ino); + + if (nino->ni_fd) + (void )close(nino->ni_fd); + free(ino->i_private); +} + +static void +yod_fsop_gone(struct filesys *fs __IS_UNUSED) +{ + + /* + * Do nothing. There is no private part maintained for the + * yod file interface. + */ +} diff --git a/libsysio/drivers/yod/fs_yod.h b/libsysio/drivers/yod/fs_yod.h new file mode 100644 index 0000000..174b82d --- /dev/null +++ b/libsysio/drivers/yod/fs_yod.h @@ -0,0 +1,48 @@ +/* + * This Cplant(TM) source code is the property of Sandia National + * Laboratories. + * + * This Cplant(TM) source code is copyrighted by Sandia National + * Laboratories. + * + * The redistribution of this Cplant(TM) source code is subject to the + * terms of the GNU Lesser General Public License + * (see cit/LGPL or http://www.gnu.org/licenses/lgpl.html) + * + * Cplant(TM) Copyright 1998-2003 Sandia Corporation. + * Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive + * license for use of this work by or on behalf of the US Government. + * Export of this program may require a license from the United States + * Government. + */ + +/* + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Questions or comments about this library should be sent to: + * + * Lee Ward + * Sandia National Laboratories, New Mexico + * P.O. Box 5800 + * Albuquerque, NM 87185-1110 + * + * lee@sandia.gov + */ + +/* + * Remote file system driver support. + */ + +extern int _sysio_yod_init(); diff --git a/libsysio/drivers/yod/module.mk b/libsysio/drivers/yod/module.mk new file mode 100644 index 0000000..1c2cc91 --- /dev/null +++ b/libsysio/drivers/yod/module.mk @@ -0,0 +1,10 @@ +if WITH_CPLANT_YOD +YOD_SRCS = drivers/yod/fs_yod.c +YOD_DRIVER_FLAGS = -DCPLANT_YOD +else +YOD_SRCS = +YOD_DRIVER_FLAGS = +endif + +# Bring yod files along in the distribution regardless +YOD_EXTRA = include/cplant-yod.h drivers/yod/fs_yod.h drivers/yod/module.mk diff --git a/libsysio/include/cplant-yod.h b/libsysio/include/cplant-yod.h new file mode 100644 index 0000000..8aa4b50 --- /dev/null +++ b/libsysio/include/cplant-yod.h @@ -0,0 +1,69 @@ +/* + * This Cplant(TM) source code is the property of Sandia National + * Laboratories. + * + * This Cplant(TM) source code is copyrighted by Sandia National + * Laboratories. + * + * The redistribution of this Cplant(TM) source code is subject to the + * terms of the GNU Lesser General Public License + * (see cit/LGPL or http://www.gnu.org/licenses/lgpl.html) + * + * Cplant(TM) Copyright 1998-2003 Sandia Corporation. + * Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive + * license for use of this work by or on behalf of the US Government. + * Export of this program may require a license from the United States + * Government. + */ + +/* + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Questions or comments about this library should be sent to: + * + * Lee Ward + * Sandia National Laboratories, New Mexico + * P.O. Box 5800 + * Albuquerque, NM 87185-1110 + * + * lee@sandia.gov + */ + +/* + * cplant yod I/O functions + */ +extern int chmod_yod(const char* path, mode_t); +extern int chown_yod(const char* path, uid_t, gid_t); +extern int stat_yod(const char *path, struct stat *sbuf); +extern int fstat_yod(int fd, struct stat *buf); +#ifdef _HAVE_STATVFS +extern int statfs_yod(const char *path, struct statfs *sbuf); +extern int fstatfs_yod(int fd, struct statfs *buf); +#endif +extern int mkdir_yod(const char *path, mode_t mode); +extern int rmdir_yod(const char *path); +extern int getdirentries_yod(int fd, char *buf, size_t nbytes, loff_t *basep); +extern int link_yod(const char *path1, const char *path2); +extern int unlink_yod(const char *path); +extern int symlink_yod(const char *path1, const char *path2 ); +extern int rename_yod( const char *path1, const char *path2 ); +extern int open_yod(const char *fname, int flags, mode_t mode); +extern int close_yod(int); +extern ssize_t write_yod(int fd, const void *buff, size_t nbytes); +extern ssize_t read_yod(int fd, void *buff, size_t nbytes); +extern int fsync_yod(int fd); +extern int truncate_yod(const char *path, off_t length); +extern int ftruncate_yod(int fd, long length); +extern off_t lseek_yod(int fd, off_t offset, int whence); diff --git a/libsysio/include/dev.h b/libsysio/include/dev.h new file mode 100644 index 0000000..0fe459b --- /dev/null +++ b/libsysio/include/dev.h @@ -0,0 +1,152 @@ +/* + * This Cplant(TM) source code is the property of Sandia National + * Laboratories. + * + * This Cplant(TM) source code is copyrighted by Sandia National + * Laboratories. + * + * The redistribution of this Cplant(TM) source code is subject to the + * terms of the GNU Lesser General Public License + * (see cit/LGPL or http://www.gnu.org/licenses/lgpl.html) + * + * Cplant(TM) Copyright 1998-2003 Sandia Corporation. + * Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive + * license for use of this work by or on behalf of the US Government. + * Export of this program may require a license from the United States + * Government. + */ + +/* + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Questions or comments about this library should be sent to: + * + * Lee Ward + * Sandia National Laboratories, New Mexico + * P.O. Box 5800 + * Albuquerque, NM 87185-1110 + * + * lee@sandia.gov + */ + +/* + * Device support. + */ + +/* + * Make a device number, composed of major and minor parts. We *assume* that + * the system version of a dev_t is 16 bits or more. + */ +#define SYSIO_MKDEV(major, minor) \ + ((((major) & 0xff) << 8) | ((minor) & 0xff)) + +/* + * Return major unit given dev number. + */ +#define SYSIO_MAJOR_DEV(dev) \ + (((dev) >> 8) & 0xff) + +/* + * Return minor unit given dev number. + */ +#define SYSIO_MINOR_DEV(dev) \ + ((dev) & 0xff) + +extern const struct inode_ops _sysio_nodev_ops; + +#define _sysio_nodev_inop_lookup \ + (int (*)(struct pnode *, \ + struct inode **, \ + struct intent *, \ + const char *))_sysio_do_illop +#define _sysio_nodev_inop_getattr \ + (int (*)(struct pnode *, \ + struct inode *, \ + struct intnl_stat *))_sysio_do_ebadf +#define _sysio_nodev_inop_setattr \ + (int (*)(struct pnode *, \ + struct inode *, \ + unsigned , \ + struct intnl_stat *))_sysio_do_ebadf +#define _sysio_nodev_getdirentries \ + (ssize_t (*)(struct inode *, \ + char *, \ + size_t , \ + _SYSIO_OFF_T *))_sysio_do_illop +#define _sysio_nodev_inop_mkdir \ + (int (*)(struct pnode *, \ + mode_t))_sysio_do_illop +#define _sysio_nodev_inop_rmdir \ + (int (*)(struct pnode *))_sysio_do_illop +#define _sysio_nodev_inop_symlink \ + (int (*)(struct pnode *, \ + const char *))_sysio_do_illop +#define _sysio_nodev_inop_readlink \ + (int (*)(struct pnode *, \ + char *, \ + size_t))_sysio_do_illop +#define _sysio_nodev_inop_open \ + (int (*)(struct pnode *, \ + int, \ + mode_t))_sysio_do_enoent +#define _sysio_nodev_inop_close \ + (int (*)(struct inode *))_sysio_do_ebadf +#define _sysio_nodev_inop_link \ + (int (*)(struct pnode *, struct pnode *))_sysio_do_illop +#define _sysio_nodev_inop_unlink \ + (int (*)(struct pnode *))_sysio_do_illop +#define _sysio_nodev_inop_rename \ + (int (*)(struct pnode *, struct pnode *))_sysio_do_illop +#define _sysio_nodev_inop_read \ + (int (*)(struct inode *, \ + struct ioctx *))_sysio_do_ebadf +#define _sysio_nodev_inop_write \ + (int (*)(struct inode *, \ + struct ioctx *))_sysio_do_ebadf +#define _sysio_nodev_inop_pos \ + (_SYSIO_OFF_T (*)(struct inode *, _SYSIO_OFF_T))_sysio_do_ebadf +#define _sysio_nodev_inop_iodone \ + (int (*)(struct ioctx *))_sysio_do_einval +#define _sysio_nodev_inop_fcntl \ + (int (*)(struct inode *, \ + int, \ + va_list))_sysio_do_ebadf +#define _sysio_nodev_inop_sync \ + (int (*)(struct inode *))_sysio_do_ebadf +#define _sysio_nodev_inop_datasync \ + (int (*)(struct inode *))_sysio_do_ebadf +#define _sysio_nodev_inop_ioctl \ + (int (*)(struct inode *, \ + unsigned long int, \ + va_list))_sysio_do_ebadf +#define _sysio_nodev_inop_mknod \ + (int (*)(struct pnode *, \ + mode_t, \ + dev_t))_sysio_do_illop +#ifdef _HAVE_STATVFS +#define _sysio_nodev_inop_statvfs \ + (int (*)(struct pnode *, \ + struct inode *, \ + struct intnl_statvfs *))_sysio_do_illop +#endif +#define _sysio_nodev_inop_gone \ + (void (*)(struct inode *ino))_sysio_do_noop + +extern int _sysio_dev_init(void); +extern dev_t _sysio_dev_alloc(void); +extern struct inode_ops *_sysio_dev_lookup(mode_t mode, dev_t dev); +extern int _sysio_char_dev_register(int major, + const char *name, + struct inode_ops *ops); diff --git a/libsysio/include/file.h b/libsysio/include/file.h new file mode 100644 index 0000000..ed15f6b --- /dev/null +++ b/libsysio/include/file.h @@ -0,0 +1,110 @@ +/* + * This Cplant(TM) source code is the property of Sandia National + * Laboratories. + * + * This Cplant(TM) source code is copyrighted by Sandia National + * Laboratories. + * + * The redistribution of this Cplant(TM) source code is subject to the + * terms of the GNU Lesser General Public License + * (see cit/LGPL or http://www.gnu.org/licenses/lgpl.html) + * + * Cplant(TM) Copyright 1998-2003 Sandia Corporation. + * Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive + * license for use of this work by or on behalf of the US Government. + * Export of this program may require a license from the United States + * Government. + */ + +/* + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Questions or comments about this library should be sent to: + * + * Lee Ward + * Sandia National Laboratories, New Mexico + * P.O. Box 5800 + * Albuquerque, NM 87185-1110 + * + * lee@sandia.gov + */ + +/* + * Open file support. + */ + +/* + * A file record is maintained for each open file in the system. It holds + * all the info necessary to track the context and parameters for the + * operations that may be performed. + */ +struct file { + struct inode *f_ino; /* path node */ + _SYSIO_OFF_T f_pos; /* current stream pos */ + unsigned f_ref; /* ref count */ + int f_flags; /* open/fcntl flags */ +}; + +/* + * Reference a file record. + */ +#define F_REF(fil) \ + do { \ + (fil)->f_ref++; \ + assert((fil)->f_ref); \ + I_REF((fil)->f_ino); \ + } while (0) + +/* + * Release reference to a file record. + */ +#define F_RELE(fil) \ + do { \ + struct inode *ino; \ + \ + assert((fil)->f_ref); \ + (fil)->f_ref--; \ + ino = (fil)->f_ino; \ + if (!(fil)->f_ref) \ + _sysio_fgone(fil); \ + I_RELE(ino); \ + } while (0) + +/* + * Init file record. + * + * NB: Don't forget to take a reference to the inode too! + */ +#define _SYSIO_FINIT(fil, ino, flags) \ + do { \ + (fil)->f_ino = (ino); \ + (fil)->f_pos = 0; \ + (fil)->f_ref = 1; \ + (fil)->f_flags = (flags); \ + } while (0) + +struct ioctx; + +extern struct file *_sysio_fnew(struct inode *ino, int flags); +extern void _sysio_fgone(struct file *fil); +extern void _sysio_fcompletio(struct ioctx *ioctx, struct file *fil); +extern int _sysio_fd_close(int fd); +extern struct file *_sysio_fd_find(int fd); +extern int _sysio_fd_set(struct file *fil, int fd); +extern int _sysio_fd_dup2(int oldfd, int newfd); +extern int _sysio_fd_close_all(void); +#if ZERO_SUM_MEMORY +extern void _sysio_fd_shutdown(void); +#endif diff --git a/libsysio/include/fs.h b/libsysio/include/fs.h new file mode 100644 index 0000000..8c7e782 --- /dev/null +++ b/libsysio/include/fs.h @@ -0,0 +1,172 @@ +/* + * This Cplant(TM) source code is the property of Sandia National + * Laboratories. + * + * This Cplant(TM) source code is copyrighted by Sandia National + * Laboratories. + * + * The redistribution of this Cplant(TM) source code is subject to the + * terms of the GNU Lesser General Public License + * (see cit/LGPL or http://www.gnu.org/licenses/lgpl.html) + * + * Cplant(TM) Copyright 1998-2003 Sandia Corporation. + * Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive + * license for use of this work by or on behalf of the US Government. + * Export of this program may require a license from the United States + * Government. + */ + +/* + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Questions or comments about this library should be sent to: + * + * Lee Ward + * Sandia National Laboratories, New Mexico + * P.O. Box 5800 + * Albuquerque, NM 87185-1110 + * + * lee@sandia.gov + */ + +/* + * File system or volume support. + */ + +struct filesys; + +struct pnode; +struct mount; + +/* + * File system switch operations. + */ +struct fssw_ops { + int (*fsswop_mount)(const char *source, + unsigned flags, + const void *data, + struct pnode *tocover, + struct mount **mntp); +}; + +/* + * File system switch entry record. + * + * Each available file system or volume access driver is represented by + * one of these switch entries in the switch. + */ +struct fsswent { + const char *fssw_name; /* entry name */ + LIST_ENTRY(fsswent) fssw_link; /* link to next */ + struct fssw_ops fssw_ops; /* operations */ +}; + +/* + * Init file system switch entry record. + */ +#define FSSWENT_INIT(fsswent, name, ops) \ + do { \ + (fsswent)->fssw_name = (name); \ + (fsswent)->fssw_ops = (ops); \ + } while (0) + +struct inode; + +/* + * File system operations. + */ +struct filesys_ops { + void (*fsop_gone)(struct filesys *); +}; + +/* + * Define the desired size of the file system record's inode table. This should + * probably be something fancy that tries to use up a system page, or the + * like. I'm not feeling adventurous right now though. It is prime though. + * That should help out the hash. + */ +#ifndef FS_ITBLSIZ +#define FS_ITBLSIZ 503 +#endif + +/* + * Inode list head record. + */ +LIST_HEAD(itable_entry, inode); + +/* + * A filesys record is maintained for each active file system or volume. + */ +struct filesys { + dev_t fs_dev; /* device ID */ + unsigned fs_ref; /* soft ref count */ + unsigned fs_flags; /* flags (see below) */ + struct filesys_ops fs_ops; /* operations */ + void *fs_private; /* driver data */ + struct itable_entry fs_itbl[FS_ITBLSIZ]; /* inodes hash */ + unsigned long fs_id; /* ID */ + size_t fs_bsize; /* block size */ +}; + +#define FS_F_RO 0x01 /* read-only */ + +/* + * Init file system record. + */ +#define FS_INIT(fs, flags, ops, private) \ + do { \ + size_t __i; \ + struct itable_entry *__head; \ + \ + (fs)->fs_ref = 1; \ + (fs)->fs_flags = (flags); \ + (fs)->fs_ops = *(ops); \ + (fs)->fs_private = (private); \ + __i = FS_ITBLSIZ; \ + __head = (fs)->fs_itbl; \ + do { \ + LIST_INIT(__head); \ + __head++; \ + } while (--__i); \ + } while (0) + +/* + * Reference file system record. + */ +#define FS_REF(fs) \ + do { \ + ++(fs)->fs_ref; \ + assert((fs)->fs_ref); \ + } while (0) + +/* + * Release reference to file system record. + */ +#define FS_RELE(fs) \ + do { \ + assert((fs)->fs_ref); \ + if (!--(fs)->fs_ref) \ + _sysio_fs_gone(fs); \ + } while (0) + +extern struct fsswent *_sysio_fssw_lookup(const char *name); +extern int _sysio_fssw_register(const char *name, struct fssw_ops *ops); +extern struct filesys * _sysio_fs_new(struct filesys_ops *ops, + unsigned mask, + void *private); +extern void _sysio_fs_gone(struct filesys *fs); +#if ZERO_SUM_MEMORY +extern void _sysio_fssw_shutdown(void); +#endif diff --git a/libsysio/include/inode.h b/libsysio/include/inode.h new file mode 100644 index 0000000..d6ee2ff --- /dev/null +++ b/libsysio/include/inode.h @@ -0,0 +1,517 @@ +/* + * This Cplant(TM) source code is the property of Sandia National + * Laboratories. + * + * This Cplant(TM) source code is copyrighted by Sandia National + * Laboratories. + * + * The redistribution of this Cplant(TM) source code is subject to the + * terms of the GNU Lesser General Public License + * (see cit/LGPL or http://www.gnu.org/licenses/lgpl.html) + * + * Cplant(TM) Copyright 1998-2003 Sandia Corporation. + * Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive + * license for use of this work by or on behalf of the US Government. + * Export of this program may require a license from the United States + * Government. + */ + +/* + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Questions or comments about this library should be sent to: + * + * Lee Ward + * Sandia National Laboratories, New Mexico + * P.O. Box 5800 + * Albuquerque, NM 87185-1110 + * + * lee@sandia.gov + */ + +#if defined(AUTOMOUNT_FILE_NAME) && !defined(MAX_MOUNT_DEPTH) +/* + * Maximum number of automounts to attempt in path traversal. + */ +#define MAX_MOUNT_DEPTH 64 +#endif + +/* + * Each i-node is uniquely identified by a file identifier, supplied by + * the relevant file system driver. The i-node number returned in the getattrs + * call is not always enough. + */ +struct file_identifier { + void *fid_data; + size_t fid_len; +}; + +struct pnode; +struct inode; +struct intent; +struct intnl_dirent; +struct intnl_stat; +#ifdef _HAVE_STATVFS +struct intnl_statvfs; +#endif +struct io_arguments; +struct ioctx; + +/* + * Operations on i-nodes. + * + * Should this be split up into file and name space operations? + */ +struct inode_ops { + int (*inop_lookup)(struct pnode *pno, + struct inode **inop, + struct intent *intnt, + const char *path); + int (*inop_getattr)(struct pnode *pno, + struct inode *ino, + struct intnl_stat *stbuf); + int (*inop_setattr)(struct pnode *pno, + struct inode *ino, + unsigned mask, + struct intnl_stat *stbuf); + ssize_t (*inop_getdirentries)(struct inode *ino, + char *buf, + size_t nbytes, + _SYSIO_OFF_T *basep); + int (*inop_mkdir)(struct pnode *pno, mode_t mode); + int (*inop_rmdir)(struct pnode *pno); + int (*inop_symlink)(struct pnode *pno, const char *data); + int (*inop_readlink)(struct pnode *pno, char *buf, size_t bufsiz); + int (*inop_open)(struct pnode *pno, int flags, mode_t mode); + int (*inop_close)(struct inode *ino); + int (*inop_link)(struct pnode *old, struct pnode *new); + int (*inop_unlink)(struct pnode *pno); + int (*inop_rename)(struct pnode *old, struct pnode *new); + int (*inop_read)(struct inode *ino, struct ioctx *ioctx); + int (*inop_write)(struct inode *ino, struct ioctx *ioctx); + _SYSIO_OFF_T (*inop_pos)(struct inode *ino, _SYSIO_OFF_T off); + int (*inop_iodone)(struct ioctx *iocp); + int (*inop_fcntl)(struct inode *ino, int cmd, va_list ap); + int (*inop_sync)(struct inode *ino); + int (*inop_datasync)(struct inode *ino); + int (*inop_ioctl)(struct inode *ino, unsigned long int request, va_list ap); + int (*inop_mknod)(struct pnode *pno, mode_t mode, dev_t dev); +#ifdef _HAVE_STATVFS + int (*inop_statvfs)(struct pnode *pno, + struct inode *ino, + struct intnl_statvfs *buf); +#endif + void (*inop_gone)(struct inode *ino); +}; + +/* + * Values for the mask to inop_setattr. + */ +#define SETATTR_MODE 0x01 +#define SETATTR_MTIME 0x02 +#define SETATTR_ATIME 0x04 +#define SETATTR_UID 0x08 +#define SETATTR_GID 0x10 +#define SETATTR_LEN 0x20 + +/* + * An i-node record is maintained for each file object in the system. + */ +struct inode { + LIST_ENTRY(inode) i_link; /* FS i-nodes link */ + unsigned + i_immune : 1, /* immune from GC */ + i_zombie : 1; /* stale inode */ + unsigned i_ref; /* soft ref counter */ + mode_t i_mode; /* mode (see stat.h) */ + dev_t i_rdev; /* dev (if device) */ + struct inode_ops i_ops; /* operations */ + struct filesys *i_fs; /* file system ptr */ + struct file_identifier *i_fid; /* file ident */ + void *i_private; /* driver data */ + TAILQ_ENTRY(inode) i_nodes; /* all i-nodes link */ +}; + +/* + * Init an i-node record. + */ +#define I_INIT(ino, fs, mode, rdev, ops, fid, immunity, private) \ + do { \ + (ino)->i_immune = (immunity) ? 1 : 0; \ + (ino)->i_zombie = 0; \ + (ino)->i_ref = 0; \ + (ino)->i_mode = (mode); \ + (ino)->i_rdev = (rdev); \ + (ino)->i_ops = *(ops); \ + (ino)->i_fs = (fs); \ + (ino)->i_fid = (fid); \ + (ino)->i_private = (private); \ + } while (0) + +/* + * Take soft reference to i-node. + */ +#define I_REF(ino) \ + do { \ + TAILQ_REMOVE(&_sysio_inodes, (ino), i_nodes); \ + TAILQ_INSERT_TAIL(&_sysio_inodes, (ino), i_nodes); \ + (ino)->i_ref++; \ + assert((ino)->i_ref); \ + } while (0) + +/* + * Release soft reference to i-node. + */ +#define I_RELE(ino) \ + do { \ + assert((ino)->i_ref); \ + if (!--(ino)->i_ref && (ino)->i_zombie) \ + _sysio_i_gone(ino); \ + } while (0) + +/* + * Attempt to kill an inode. + */ +#define I_GONE(ino) \ + do { \ + _sysio_i_undead(ino); \ + I_RELE(ino); \ + } while (0) + +/* + * The "quick string" record (inspired by the structure of the same name + * from Linux) is used to pass a string without delimiters as well as useful + * information about the string. + */ +struct qstr { + const char *name; + size_t len; + unsigned hashval; +}; + +/* + * A path node is an entry in a directory. It may have many aliases, one + * for each name space in which it occurs. This record holds the + * common information. + */ +struct pnode_base { + struct qstr pb_name; /* entry name */ + struct inode *pb_ino; /* inode */ + LIST_HEAD(, pnode_base) pb_children; /* children if a dir */ + LIST_ENTRY(pnode_base) pb_sibs; /* links to siblings */ + LIST_ENTRY(pnode_base) pb_names; /* near names links */ + LIST_HEAD(, pnode) pb_aliases; /* aliases */ + struct pnode_base *pb_parent; /* parent */ +}; + +/* + * Since a file system may be multiply mounted, in different parts of the local + * tree, a file system object may appear in different places. We handle that + * with aliases. There is one pnode for every alias the system is tracking. + * + * Name space traversal depends heavily on the interpretation of many + * of the fields in this structure. For that reason a detailed discussion + * of the various fields is given. + * + * The reference field records soft references to the record. For instance, + * it tracks file and directory opens. It does not track sibling references, + * though, as those are hard references and can be found by examining the + * aliases list in the base part of the node. + * + * The parent value points to the parent directory for this entry, in the + * *system* name space -- Not the mounted volumes. If you want to examine + * the moutned volume name space, use the base record. + * + * The base value points to the base path node information. It is info common + * to all of the aliases. + * + * The mount value points to the mount record for the rooted name space in + * which the alias is found. Notably, if a node is the root of a sub-tree then + * the mount record, among other things, indicates another node + * (in another sub-tree) that is covered by this one. + * + * Another sub-tree, mounted on this node, is indicated by a non-null cover. + * The pnode pointed to, then, is the root of the mounted sub-tree. + * + * The links list entry holds pointers to other aliases for the base path + * node entry. + * + * The nodes link is bookkeeping. + */ +struct pnode { + unsigned p_ref; /* soft ref count */ + struct pnode *p_parent; /* parent */ + struct pnode_base *p_base; /* base part */ + struct mount *p_mount; /* mount info */ + struct pnode *p_cover; /* covering pnode */ + LIST_ENTRY(pnode) p_links; /* other aliases */ + TAILQ_ENTRY(pnode) p_nodes; /* all nodes links */ +}; + +/* + * Reference path-tree node. + */ +#define P_REF(pno) \ + do { \ + TAILQ_REMOVE(&_sysio_pnodes, (pno), p_nodes); \ + TAILQ_INSERT_TAIL(&_sysio_pnodes, (pno), p_nodes); \ + (pno)->p_ref++; \ + assert((pno)->p_ref); \ + } while (0) + +/* + * Release reference to path-tree node. + */ +#define P_RELE(pno) \ + do { \ + assert((pno)->p_ref); \ + --(pno)->p_ref; \ + } while (0) + +/* + * An intent record allows callers of namei and lookup to pass some information + * about what they want to accomplish in the end. + */ +struct intent { + unsigned int_opmask; + void *int_arg1; + void *int_arg2; +}; + +/* + * Intent operations. + */ +#define INT_GETATTR 0x01 /* get attrs */ +#define INT_SETATTR 0x02 /* set attrs */ +#define INT_UPDPARENT 0x04 /* insert/delete */ +#define INT_OPEN 0x08 /* open */ +#define INT_CREAT (INT_UPDPARENT|0x10) /* insert */ +#define INT_READLINK 0x12 /* readlink */ + +#define INTENT_INIT(intnt, mask, arg1, arg2) \ + do { \ + (intnt)->int_opmask = (mask); \ + (intnt)->int_arg1 = (arg1); \ + (intnt)->int_arg2 = (arg2); \ + } while (0) + +/* + * Bundled up arguments to _sysio_path_walk. + */ +struct nameidata { + unsigned nd_flags; /* flags (see below) */ + const char *nd_path; /* path arg */ + struct pnode *nd_pno; /* returned pnode */ + struct pnode *nd_root; /* system/user root */ + struct intent *nd_intent; /* intent (NULL ok) */ + unsigned nd_slicnt; /* symlink indirects */ +#ifdef AUTOMOUNT_FILE_NAME + unsigned nd_amcnt; /* automounts */ +#endif +}; + +/* + * Values for nameidata flags field. + */ +#define ND_NOFOLLOW 0x01 /* no follow symlinks */ +#define ND_NEGOK 0x02 /* last missing is ok */ + +#ifdef AUTOMOUNT_FILE_NAME +#define _ND_INIT_AUTOMOUNT(nd) ((nd)->nd_amcnt = 0) +#else +#define _ND_INIT_AUTOMOUNT(nd) +#endif + +#define _ND_INIT_OTHERS(nd) \ + _ND_INIT_AUTOMOUNT(nd) + +/* + * Init nameidata record. + */ +#define ND_INIT(nd, flags, path, root, intnt) \ + do { \ + (nd)->nd_flags = (flags); \ + (nd)->nd_path = (path); \ + (nd)->nd_pno = NULL; \ + (nd)->nd_root = (root); \ + (nd)->nd_intent = (intnt); \ + (nd)->nd_slicnt = 0; \ + _ND_INIT_OTHERS(nd); \ + } while (0) + +/* + * IO completion callback record. + */ +struct ioctx_callback { + TAILQ_ENTRY(ioctx_callback) iocb_next; /* list link */ + void (*iocb_f)(struct ioctx *, void *); /* cb func */ + void *iocb_data; /* cb data */ +}; + +/* + * All IO internally is done with an asynchronous mechanism. This record + * holds the completion information. It's too big :-( + */ +struct ioctx { + LIST_ENTRY(ioctx) ioctx_link; /* AIO list link */ + unsigned + ioctx_fast : 1, /* from stack space */ + ioctx_done : 1, /* transfer complete */ + ioctx_write : 1; /* op is a write */ + ioid_t ioctx_id; /* unique ident */ + struct inode *ioctx_ino; /* i-node */ + const struct iovec *ioctx_iov; /* scatter/gather vec */ + size_t ioctx_iovlen; /* iovec length */ + const struct intnl_xtvec *ioctx_xtv; /* extents */ + size_t ioctx_xtvlen; /* xtv length */ + ssize_t ioctx_cc; /* rtn char count */ + int ioctx_errno; /* error number */ + TAILQ_HEAD(, ioctx_callback) ioctx_cbq; /* callback queue */ + void *ioctx_private; /* driver data */ +}; + +/* + * Init IO context record. + */ +#define IOCTX_INIT(ioctx, fast, id, wr, ino, iov, iovlen, xtv, xtvlen) \ + do { \ + (ioctx)->ioctx_fast = (fast); \ + (ioctx)->ioctx_done = 0; \ + (ioctx)->ioctx_write = (wr) ? 1 : 0; \ + (ioctx)->ioctx_id = (id); \ + (ioctx)->ioctx_ino = (ino); \ + (ioctx)->ioctx_iov = (iov); \ + (ioctx)->ioctx_iovlen = (iovlen); \ + (ioctx)->ioctx_xtv = (xtv); \ + (ioctx)->ioctx_xtvlen = (xtvlen); \ + (ioctx)->ioctx_cc = 0; \ + (ioctx)->ioctx_errno = 0; \ + TAILQ_INIT(&(ioctx)->ioctx_cbq); \ + (ioctx)->ioctx_private = NULL; \ + } while (0) + +/* + * Return whether a pnode/inode is on a read-only mount or file system. + */ +#define IS_RDONLY(pno, ino) \ + ((((struct pnode *)(pno)) && \ + ((((struct pnode *)(pno))->p_mount->mnt_flags & MOUNT_F_RO) || \ + (((struct pnode *)(pno))->p_base->pb_ino && \ + (((struct pnode *)(pno))->p_base->pb_ino->i_fs->fs_flags & \ + FS_F_RO)))) || \ + (((struct inode *)(ino)) && \ + (((struct inode *)(ino))->i_fs->fs_flags & FS_F_RO))) + +extern struct pnode *_sysio_root; + +extern TAILQ_HEAD(inodes_head, inode) _sysio_inodes; +extern TAILQ_HEAD(pnodes_head, pnode) _sysio_pnodes; + +extern int _sysio_i_init(void); +#if ZERO_SUM_MEMORY +extern void _sysio_i_shutdown(void); +#endif +extern struct inode *_sysio_i_new(struct filesys *fs, + struct file_identifier *fid, + mode_t type, + dev_t rdev, + unsigned immunity, + struct inode_ops *ops, + void *private); +extern struct inode *_sysio_i_find(struct filesys *fs, + struct file_identifier *fid); +extern void _sysio_i_gone(struct inode *ino); +extern void _sysio_i_undead(struct inode *ino); +extern int _sysio_p_find_alias(struct pnode *parent, + struct qstr *name, + struct pnode **pnop); +extern int _sysio_p_validate(struct pnode *pno, + struct intent *intnt, + const char *path); +extern struct pnode_base *_sysio_pb_new(struct qstr *name, + struct pnode_base *parent, + struct inode *ino); +extern void _sysio_pb_gone(struct pnode_base *pb); +extern struct pnode *_sysio_p_new_alias(struct pnode *parent, + struct pnode_base *pb, + struct mount *mnt); +extern void _sysio_p_gone(struct pnode *pno); +extern size_t _sysio_p_prune(struct pnode *root); +extern int _sysio_p_kill_all(struct pnode *root); +extern char *_sysio_pb_path(struct pnode_base *pb, char separator); +extern int _sysio_setattr(struct pnode *pno, + struct inode *ino, + unsigned mask, + struct intnl_stat *stbuf); +extern void _sysio_do_noop(void); +extern void _sysio_do_illop(void); +extern int _sysio_do_ebadf(void); +extern int _sysio_do_einval(void); +extern int _sysio_do_enoent(void); +extern int _sysio_do_espipe(void); +extern int _sysio_do_eisdir(void); +extern int _sysio_do_enosys(void); +extern int _sysio_path_walk(struct pnode *parent, struct nameidata *nd); +#ifdef AUTOMOUNT_FILE_NAME +extern void _sysio_next_component(const char *path, struct qstr *name); +#endif +extern int _sysio_namei(struct pnode *pno, + const char *path, + unsigned flags, + struct intent *intnt, + struct pnode **pnop); +extern int _sysio_p_chdir(struct pnode *pno); +extern int _sysio_ioctx_init(void); +extern void _sysio_ioctx_enter(struct ioctx *ioctx); +extern struct ioctx *_sysio_ioctx_new(struct inode *ino, + int wr, + const struct iovec *iov, + size_t iovlen, + const struct intnl_xtvec *xtv, + size_t xtvlen); +extern int _sysio_ioctx_cb(struct ioctx *ioctx, + void (*f)(struct ioctx *, void *), + void *data); +extern void _sysio_ioctx_cb_free(struct ioctx_callback *cb); +extern struct ioctx *_sysio_ioctx_find(ioid_t id); +extern ssize_t _sysio_ioctx_wait(struct ioctx *ioctx); +extern void _sysio_ioctx_complete(struct ioctx *ioctx); +extern ssize_t _sysio_validx(const struct intnl_xtvec *xtv, size_t xtvlen, + const struct iovec *iov, size_t iovlen, + _SYSIO_OFF_T limit); +extern ssize_t _sysio_enumerate_extents(const struct intnl_xtvec *xtv, + size_t xtvlen, + const struct iovec *iov, + size_t iovlen, + ssize_t (*f)(const struct iovec *, + int, + _SYSIO_OFF_T, + ssize_t, + void *), + void *arg); +extern ssize_t _sysio_enumerate_iovec(const struct iovec *iov, + size_t count, + _SYSIO_OFF_T off, + ssize_t limit, + ssize_t (*f)(void *, + size_t, + _SYSIO_OFF_T, + void *), + void *arg); +extern ssize_t _sysio_doio(const struct intnl_xtvec *xtv, size_t xtvlen, + const struct iovec *iov, size_t iovlen, + ssize_t (*f)(void *, size_t, _SYSIO_OFF_T, void *), + void *arg); +extern int _sysio_open(struct pnode *pno, int flags, mode_t mode); diff --git a/libsysio/include/module.mk b/libsysio/include/module.mk new file mode 100644 index 0000000..ce1c427 --- /dev/null +++ b/libsysio/include/module.mk @@ -0,0 +1,4 @@ +INCLUDE_EXTRA = include/dev.h include/file.h include/fs.h \ + include/inode.h include/mount.h include/sysio.h \ + include/sysio-symbols.h include/cplant-yod.h \ + include/module.mk include/xtio.h diff --git a/libsysio/include/mount.h b/libsysio/include/mount.h new file mode 100644 index 0000000..24f631d --- /dev/null +++ b/libsysio/include/mount.h @@ -0,0 +1,98 @@ +/* + * This Cplant(TM) source code is the property of Sandia National + * Laboratories. + * + * This Cplant(TM) source code is copyrighted by Sandia National + * Laboratories. + * + * The redistribution of this Cplant(TM) source code is subject to the + * terms of the GNU Lesser General Public License + * (see cit/LGPL or http://www.gnu.org/licenses/lgpl.html) + * + * Cplant(TM) Copyright 1998-2003 Sandia Corporation. + * Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive + * license for use of this work by or on behalf of the US Government. + * Export of this program may require a license from the United States + * Government. + */ + +/* + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Questions or comments about this library should be sent to: + * + * Lee Ward + * Sandia National Laboratories, New Mexico + * P.O. Box 5800 + * Albuquerque, NM 87185-1110 + * + * lee@sandia.gov + */ + +/* + * Mount support. + */ + +struct filesys; +struct pnode; + +/* + * Each file system may be mounted multiple times and in various places + * in the name space. The mount record maintains the binding information + * between the system name space and the file system's. + */ +struct mount { + struct filesys *mnt_fs; /* file system */ + unsigned mnt_flags; /* flags (see below) */ + struct pnode *mnt_root; /* fs sub-tree root */ + struct pnode *mnt_covers; /* covered pnode */ + LIST_ENTRY(mount) mnt_link; /* link to next */ +}; + +/* + * Mount flags definitions. + */ +#define MOUNT_F_RO 0x01 /* read-only */ +#ifdef AUTOMOUNT_FILE_NAME +#define MOUNT_F_AUTO 0x02 /* automount enabled */ +#endif + +#ifdef AUTOMOUNT_FILE_NAME +extern struct qstr _sysio_mount_file_name; +#endif + +struct pnode_base; + +extern int _sysio_mount_init(void); +extern int _sysio_do_mount(struct filesys *fs, + struct pnode_base *rootpb, + unsigned flags, + struct pnode *tocover, + struct mount **mntp); +extern int _sysio_do_unmount(struct mount *fs); +extern int _sysio_mount_root(const char *source, + const char *type, + unsigned flags, + const void *data); +extern int _sysio_mount(struct pnode *cwd, + const char *source, + const char *target, + const char *filesystemtype, + unsigned long mountflags, + const void *data); +extern int _sysio_unmount_all(void); +#ifdef AUTOMOUNT_FILE_NAME +extern int _sysio_automount(struct pnode *mntpno); +#endif diff --git a/libsysio/include/namespace.h b/libsysio/include/namespace.h new file mode 100644 index 0000000..23c1f78 --- /dev/null +++ b/libsysio/include/namespace.h @@ -0,0 +1,30 @@ +/* + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Questions or comments about this library should be sent to: + * + * Lee Ward + * Sandia National Laboratories, New Mexico + * P.O. Box 5800 + * Albuquerque, NM 87185-1110 + * + * lee@sandia.gov + */ + +/* + * Boot time namespace assembly function + */ +extern int run_cmds(char *buf); + diff --git a/libsysio/include/sysio-symbols.h b/libsysio/include/sysio-symbols.h new file mode 100644 index 0000000..4b7cf56 --- /dev/null +++ b/libsysio/include/sysio-symbols.h @@ -0,0 +1,26 @@ +#if defined(HAVE_ASM_WEAK_DIRECTIVE) || defined(HAVE_ASM_WEAKEXT_DIRECTIVE) +#define HAVE_WEAK_SYMBOLS +#endif + +#define STRINGOF(x) #x + +/* + * Define alias, asym, as a strong alias for symbol, sym. + */ +#define sysio_sym_strong_alias(sym, asym) \ + extern __typeof(sym) asym __attribute__((alias(STRINGOF(sym)))); + +#ifdef HAVE_WEAK_SYMBOLS + +/* + * Define alias, asym, as a strong alias for symbol, sym. + */ +#define sysio_sym_weak_alias(sym, asym) \ + extern __typeof(sym) asym __attribute__((weak, alias(STRINGOF(sym)))); +#else /* !defined(HAVE_ASM_WEAK_DIRECTIVE) */ + +/* + * Weak symbols not supported. Make it a strong alias then. + */ +#define sysio_sym_weak_alias(sym, asym) sysio_sym_strong_alias(sym, asym) +#endif diff --git a/libsysio/include/sysio.h b/libsysio/include/sysio.h new file mode 100644 index 0000000..fb05d75 --- /dev/null +++ b/libsysio/include/sysio.h @@ -0,0 +1,400 @@ +/* + * This Cplant(TM) source code is the property of Sandia National + * Laboratories. + * + * This Cplant(TM) source code is copyrighted by Sandia National + * Laboratories. + * + * The redistribution of this Cplant(TM) source code is subject to the + * terms of the GNU Lesser General Public License + * (see cit/LGPL or http://www.gnu.org/licenses/lgpl.html) + * + * Cplant(TM) Copyright 1998-2004 Sandia Corporation. + * Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive + * license for use of this work by or on behalf of the US Government. + * Export of this program may require a license from the United States + * Government. + */ + +/* + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Questions or comments about this library should be sent to: + * + * Lee Ward + * Sandia National Laboratories, New Mexico + * P.O. Box 5800 + * Albuquerque, NM 87185-1110 + * + * lee@sandia.gov + */ + +/* + * System IO common information. + */ + +#include +#include + +#ifndef _IOID_T_DEFINED +#define _IOID_T_DEFINED +/* + * FIXME: + * + * This section about ioid_t and it's failure belong in + */ +typedef void *ioid_t; + +#define IOID_FAIL 0 +#endif + +#if !defined(__IS_UNUSED) && defined(__GNUC__) +#define __IS_UNUSED __attribute__ ((unused)) +#else +#define __IS_UNUSED +#endif + +#ifndef PATH_SEPARATOR +/* + * Path separator. + */ +#define PATH_SEPARATOR '/' +#endif + +#ifndef MAX_SYMLINK +/* + * Max recursion depth allowed when resoving symbolic links. + */ +#define MAX_SYMLINK 250 +#endif + +#ifndef _LARGEFILE64_SOURCE +/* + * Not glibc I guess. Define this ourselves. + */ +#define _LARGEFILE64_SOURCE 0 +#endif + +/* + * Define internal file-offset type and it's maximum value. + */ +#if _LARGEFILE64_SOURCE +#define _SYSIO_OFF_T off64_t +#ifdef LLONG_MAX +#define _SYSIO_OFF_T_MAX (LLONG_MAX) +#else +/* + * Don't have LLONG_MAX before C99. We'll need to define it ourselves. + */ +#define _SYSIO_OFF_T_MAX (9223372036854775807LL) +#endif +#else +#define _SYSIO_OFF_T off_t +#define _SYSIO_OFF_T_MAX LONG_MAX +#endif + +/* + * Internally, all directory entries are carried in the 64-bit capable + * structure. + */ +#if _LARGEFILE64_SOURCE +#define intnl_dirent dirent64 +#else +#define intnl_dirent dirent +#endif +struct dirent; + +/* + * Internally, all file status is carried in the 64-bit capable + * structure. + */ +#if _LARGEFILE64_SOURCE +#define intnl_stat stat64 +#else +#define intnl_stat stat +#endif +struct stat; + +#ifdef _HAVE_STATVFS +#if _LARGEFILE64_SOURCE +#define intnl_statvfs statvfs64 +#else +#define intnl_statvfs statvfs +#define INTNL_STATVFS_IS_NATURAL 1 +#endif +struct statvfs; +struct intnl_statvfs; +#endif + +/* + * Internally, all file status is carried in the 64-bit capable + * structure. + */ +#if _LARGEFILE64_SOURCE +#define intnl_xtvec xtvec64 +#else +#define intnl_xtvec xtvec +#endif +struct intnl_xtvec; + +struct iovec; + +struct utimbuf; + +struct intnl_stat; + +struct pnode; + +extern struct pnode *_sysio_cwd; + +extern mode_t _sysio_umask; + +extern int _sysio_init(void); +extern void _sysio_shutdown(void); +extern int _sysio_boot(const char *buf); + +/* + * SYSIO name label macros + */ +#define XPREPEND(p,x) p ## x +#define PREPEND(p,x) XPREPEND(p,x) +#define SYSIO_LABEL_NAMES 0 +#if SYSIO_LABEL_NAMES +#define SYSIO_INTERFACE_NAME(x) PREPEND(sysio__, x) +#else +#define SYSIO_INTERFACE_NAME(x) x +#endif + +/* + * The following should be defined by the system includes, and probably are, + * but it's not illegal to have multiple externs, so long as they are the + * same. It helps when building the library in a standalone fashion. + */ +extern int SYSIO_INTERFACE_NAME(access)(const char *path, int amode); +extern int SYSIO_INTERFACE_NAME(chdir)(const char *path); +extern int SYSIO_INTERFACE_NAME(chmod)(const char *path, mode_t mode); +extern int SYSIO_INTERFACE_NAME(fchmod)(int fd, mode_t mode); +extern int SYSIO_INTERFACE_NAME(chown)(const char *path, uid_t owner, + gid_t group); +extern int SYSIO_INTERFACE_NAME(fchown)(int fd, uid_t owner, gid_t group); +extern int SYSIO_INTERFACE_NAME(close)(int d); +extern int SYSIO_INTERFACE_NAME(dup)(int oldfd); +extern int SYSIO_INTERFACE_NAME(dup2)(int oldfd, int newfd); +extern int SYSIO_INTERFACE_NAME(fcntl)(int fd, int cmd, ...); +extern int SYSIO_INTERFACE_NAME(fstat)(int fd, struct stat *buf); +extern int SYSIO_INTERFACE_NAME(fsync)(int fd); +extern char *SYSIO_INTERFACE_NAME(getcwd)(char *buf, size_t size); +extern off_t SYSIO_INTERFACE_NAME(lseek)(int fd, off_t offset, int whence); +#if _LARGEFILE64_SOURCE +extern off64_t SYSIO_INTERFACE_NAME(lseek64)(int fd, off64_t offset, + int whence); +#endif +extern int SYSIO_INTERFACE_NAME(lstat)(const char *path, struct stat *buf); +#ifdef BSD +extern int SYSIO_INTERFACE_NAME(getdirentries)(int fd, char *buf, int nbytes , + long *basep); +#else +extern ssize_t SYSIO_INTERFACE_NAME(getdirentries)(int fd, char *buf, + size_t nbytes, off_t *basep); +#if _LARGEFILE64_SOURCE +extern ssize_t SYSIO_INTERFACE_NAME(getdirentries64)(int fd, + char *buf, + size_t nbytes, + off64_t *basep); +#endif +#endif +extern int SYSIO_INTERFACE_NAME(mkdir)(const char *path, mode_t mode); +extern int SYSIO_INTERFACE_NAME(open)(const char *path, int flag, ...); +#if _LARGEFILE64_SOURCE +extern int SYSIO_INTERFACE_NAME(open64)(const char *path, int flag, ...); +#endif +extern int SYSIO_INTERFACE_NAME(creat)(const char *path, mode_t mode); +#if _LARGEFILE64_SOURCE +extern int SYSIO_INTERFACE_NAME(creat64)(const char *path, mode_t mode); +#endif +extern int SYSIO_INTERFACE_NAME(stat)(const char *path, struct stat *buf); +#if _LARGEFILE64_SOURCE +extern int SYSIO_INTERFACE_NAME(stat64)(const char *path, struct stat64 *buf); +#endif +#ifdef _HAVE_STATVFS +extern int SYSIO_INTERFACE_NAME(statvfs)(const char *path, struct statvfs *buf); +#if _LARGEFILE64_SOURCE +extern int SYSIO_INTERFACE_NAME(statvfs64)(const char *path, + struct statvfs64 *buf); +#endif +extern int SYSIO_INTERFACE_NAME(fstatvfs)(int fd, struct statvfs *buf); +#if _LARGEFILE64_SOURCE +extern int SYSIO_INTERFACE_NAME(fstatvfs64)(int fd, struct statvfs64 *buf); +#endif +#endif +extern int SYSIO_INTERFACE_NAME(truncate)(const char *path, off_t length); +#if _LARGEFILE64_SOURCE +extern int SYSIO_INTERFACE_NAME(truncate64)(const char *path, off64_t length); +#endif +extern int SYSIO_INTERFACE_NAME(ftruncate)(int fd, off_t length); +#if _LARGEFILE64_SOURCE +extern int SYSIO_INTERFACE_NAME(ftruncate64)(int fd, off64_t length); +#endif +extern int SYSIO_INTERFACE_NAME(rmdir)(const char *path); +extern int SYSIO_INTERFACE_NAME(symlink)(const char *path1, const char *path2); +extern int SYSIO_INTERFACE_NAME(readlink)(const char *path, + char *buf, + size_t bufsiz); +extern int SYSIO_INTERFACE_NAME(link)(const char *oldpath, const char *newpath); +extern int SYSIO_INTERFACE_NAME(unlink)(const char *path); +extern int SYSIO_INTERFACE_NAME(rename)(const char *oldpath, + const char *newpath); +extern int SYSIO_INTERFACE_NAME(fdatasync)(int fd); +extern int SYSIO_INTERFACE_NAME(ioctl)(int fd, unsigned long request, ...); +extern mode_t SYSIO_INTERFACE_NAME(umask)(mode_t mask); +extern int SYSIO_INTERFACE_NAME(iodone)(ioid_t ioid); +extern ssize_t SYSIO_INTERFACE_NAME(iowait)(ioid_t ioid); +extern ioid_t SYSIO_INTERFACE_NAME(ipreadv)(int fd, const struct iovec *iov, + size_t count, off_t offset); +#if _LARGEFILE64_SOURCE +extern ioid_t SYSIO_INTERFACE_NAME(ipread64v)(int fd, const struct iovec *iov, + size_t count, off64_t offset); +#endif +extern ioid_t SYSIO_INTERFACE_NAME(ipread)(int fd, void *buf, size_t count, + off_t offset); +#if _LARGEFILE64_SOURCE +extern ioid_t SYSIO_INTERFACE_NAME(ipread64)(int fd, void *buf, size_t count, + off64_t offset); +#endif +extern ssize_t SYSIO_INTERFACE_NAME(preadv)(int fd, const struct iovec *iov, + size_t count, off_t offset); +#if _LARGEFILE64_SOURCE +extern ssize_t SYSIO_INTERFACE_NAME(pread64v)(int fd, const struct iovec *iov, + size_t count, off64_t offset); +#endif +extern ssize_t SYSIO_INTERFACE_NAME(pread)(int fd, void *buf, size_t count, + off_t offset); +#if _LARGEFILE64_SOURCE +extern ssize_t SYSIO_INTERFACE_NAME(pread64)(int fd, void *buf, size_t count, + off64_t offset); +#endif +extern ioid_t SYSIO_INTERFACE_NAME(ireadv)(int fd, const struct iovec *iov, + int count); +extern ioid_t SYSIO_INTERFACE_NAME(iread)(int fd, void *buf, size_t count); +extern ssize_t SYSIO_INTERFACE_NAME(readv)(int fd, const struct iovec *iov, + int count); +extern ssize_t SYSIO_INTERFACE_NAME(read)(int fd, void *buf, size_t count); +extern ioid_t SYSIO_INTERFACE_NAME(ipwritev)(int fd, const struct iovec *iov, + size_t count, off_t offset); +#if _LARGEFILE64_SOURCE +extern ioid_t SYSIO_INTERFACE_NAME(ipwrite64v)(int fd, const struct iovec *iov, + size_t count, off64_t offset); +#endif +extern ioid_t SYSIO_INTERFACE_NAME(ipwrite)(int fd, const void *buf, + size_t count, off_t offset); +#if _LARGEFILE64_SOURCE +extern ioid_t SYSIO_INTERFACE_NAME(ipwrite64)(int fd, const void *buf, + size_t count, off64_t offset); +#endif +extern ssize_t SYSIO_INTERFACE_NAME(pwritev)(int fd, const struct iovec *iov, + size_t count, off_t offset); +#if _LARGEFILE64_SOURCE +extern ssize_t SYSIO_INTERFACE_NAME(pwrite64v)(int fd, const struct iovec *iov, + size_t count, off64_t offset); +#endif +extern ssize_t SYSIO_INTERFACE_NAME(pwrite)(int fd, const void *buf, + size_t count, off_t offset); +#if _LARGEFILE64_SOURCE +extern ssize_t SYSIO_INTERFACE_NAME(pwrite64)(int fd, const void *buf, + size_t count, off64_t offset); +#endif +extern ioid_t SYSIO_INTERFACE_NAME(iwritev)(int fd, + const struct iovec *iov, + int count); +extern ioid_t SYSIO_INTERFACE_NAME(iwrite)(int fd, const void *buf, + size_t count); +extern ssize_t SYSIO_INTERFACE_NAME(writev)(int fd, const struct iovec *iov, + int count); +extern ssize_t SYSIO_INTERFACE_NAME(write)(int fd, const void *buf, + size_t count); +extern int SYSIO_INTERFACE_NAME(mknod)(const char *path, + mode_t mode, dev_t dev); +extern int SYSIO_INTERFACE_NAME(utime)(const char *path, + const struct utimbuf *buf); +extern int SYSIO_INTERFACE_NAME(mount)(const char *source, const char *target, + const char *filesystemtype, + unsigned long mountflags, + const void *data); +extern int SYSIO_INTERFACE_NAME(umount)(const char *target); + +/* for debugging */ +#if 0 +#define ASSERT(cond) \ + if (!(cond)) { \ + printf("ASSERTION(" #cond ") failed: " __FILE__ ":" \ + __FUNCTION__ ":%d\n", __LINE__); \ + abort(); \ + } + +#define ERROR(fmt, a...) \ + do { \ + printf("ERROR(" __FILE__ ":%d):" fmt, __LINE__, ##a); \ + while(0) + +#else +#define ERROR(fmt) do{}while(0) +#define ASSERT do{}while(0) +#endif + +/* + * SYSIO interface frame macros + * + * + DISPLAY_BLOCK; Allocates storage on the stack for use by the set of + * macros. + * + ENTER; Performs entry point work + * + RETURN; Returns a value and performs exit point work + * + * NB: For RETURN, the arguments are the return value and value for errno. + * If the value for errno is non-zero then that value, *negated*, is set + * into errno. + */ +#define SYSIO_INTERFACE_DISPLAY_BLOCK \ + int _saved_errno; +#define SYSIO_INTERFACE_ENTER \ + do { \ + _saved_errno = errno; \ + SYSIO_ENTER; \ + } while (0) +#define SYSIO_INTERFACE_RETURN(rtn, err) \ + do { \ + SYSIO_LEAVE; \ + errno = (err) ? -(err) : _saved_errno; \ + return (rtn); \ + } while(0) + +/* syscall enter/leave hook functions */ +#if 0 +extern void _sysio_sysenter(); +extern void _sysio_sysleave(); + +#define SYSIO_ENTER \ + do { \ + _sysio_sysenter(); \ + } while(0) + +#define SYSIO_LEAVE \ + do { \ + _sysio_sysleave(); \ + } while(0) +#else +#define SYSIO_ENTER +#define SYSIO_LEAVE + +#endif diff --git a/libsysio/include/xtio.h b/libsysio/include/xtio.h new file mode 100644 index 0000000..765aaf8 --- /dev/null +++ b/libsysio/include/xtio.h @@ -0,0 +1,110 @@ +/* + * This Cplant(TM) source code is the property of Sandia National + * Laboratories. + * + * This Cplant(TM) source code is copyrighted by Sandia National + * Laboratories. + * + * The redistribution of this Cplant(TM) source code is subject to the + * terms of the GNU Lesser General Public License + * (see cit/LGPL or http://www.gnu.org/licenses/lgpl.html) + * + * Cplant(TM) Copyright 1998-2004 Sandia Corporation. + * Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive + * license for use of this work by or on behalf of the US Government. + * Export of this program may require a license from the United States + * Government. + */ + +/* + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Questions or comments about this library should be sent to: + * + * Lee Ward + * Sandia National Laboratories, New Mexico + * P.O. Box 5800 + * Albuquerque, NM 87185-1110 + * + * lee@sandia.gov + */ + +/* + * Structure for strided I/O. + */ +struct xtvec { +#ifndef __USE_FILE_OFFSET64 + __off_t xtv_off; /* Stride/Extent offset. */ +#else + __off64_t xtv_off; /* Stride/Extent offset. */ +#endif + size_t xtv_len; /* Stride/Extent length. */ +}; + +#ifdef __USE_LARGEFILE64 +struct xtvec64 { + __off64_t xtv_off; /* Stride/Extent offset. */ + size_t xtv_len; /* Stride/Extent length. */ +}; +#endif + +extern ioid_t SYSIO_INTERFACE_NAME(ireadx)(int fd, + const struct iovec *iov, + size_t iov_count, + const struct xtvec *xtv, + size_t xtv_count); +#ifdef __USE_LARGEFILE64 +extern ioid_t SYSIO_INTERFACE_NAME(iread64x)(int fd, + const struct iovec *iov, + size_t iov_count, + const struct xtvec64 *xtv, + size_t xtv_count); +#endif +extern ssize_t SYSIO_INTERFACE_NAME(readx)(int fd, + const struct iovec *iov, + size_t iov_count, + const struct xtvec *xtv, + size_t xtv_count); +#ifdef __USE_LARGEFILE64 +extern ssize_t SYSIO_INTERFACE_NAME(read64x)(int fd, + const struct iovec *iov, + size_t iov_count, + const struct xtvec64 *xtv, + size_t xtv_count); +#endif +extern ioid_t SYSIO_INTERFACE_NAME(iwritex)(int fd, + const struct iovec *iov, + size_t iov_count, + const struct xtvec *xtv, + size_t xtv_count); +#ifdef __USE_LARGEFILE64 +extern ioid_t SYSIO_INTERFACE_NAME(iwrite64x)(int fd, + const struct iovec *iov, + size_t iov_count, + const struct xtvec64 *xtv, + size_t xtv_count); +#endif +extern ssize_t SYSIO_INTERFACE_NAME(writex)(int fd, + const struct iovec *iov, + size_t iov_count, + const struct xtvec *xtv, + size_t xtv_count); +#ifdef __USE_LARGEFILE64 +extern ssize_t SYSIO_INTERFACE_NAME(write64x)(int fd, + const struct iovec *iov, + size_t iov_count, + const struct xtvec64 *xtv, + size_t xtv_count); +#endif diff --git a/libsysio/misc/gdb-libsysio b/libsysio/misc/gdb-libsysio new file mode 100644 index 0000000..dd3f613 --- /dev/null +++ b/libsysio/misc/gdb-libsysio @@ -0,0 +1,127 @@ +# This Cplant(TM) source code is the property of Sandia National +# Laboratories. +# +# This Cplant(TM) source code is copyrighted by Sandia National +# Laboratories. +# +# The redistribution of this Cplant(TM) source code is subject to the +# terms of the GNU Lesser General Public License +# (see cit/LGPL or http://www.gnu.org/licenses/lgpl.html) +# +# Cplant(TM) Copyright 1998-2003 Sandia Corporation. +# Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive +# license for use of this work by or on behalf of the US Government. +# Export of this program may require a license from the United States +# Government. + +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# Questions or comments about this library should be sent to: +# +# Lee Ward +# Sandia National Laboratories, New Mexico +# P.O. Box 5800 +# Albuquerque, NM 87185-1110 +# +# lee@sandia.gov + +# +# Useful commands for debugging libsysio in gdb +# + +define x_dump_pbnode + printf "%p: ", $arg0 + if $arg0->pb_name.name + printf " \"%s\"", \ + $arg0->pb_name.name + else + printf " " + 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 +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 +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 +end + +define x_dump_mounts + set $__x_dump_mounts_var_mnt = mounts.lh_first + while $__x_dump_mounts_var_mnt + x_dump_mount $__x_dump_mounts_var_mnt + set $__x_dump_mounts_var_mnt = \ + $__x_dump_mounts_var_mnt->mnt_link.le_next + end +end +document x_dump_mounts +Dump the contents of the libsysio mount table + +Usage: x_dump_mounts +end + +define x_dump_pnodes + set $_x_dump_pnodes_var_pno = _sysio_pnodes.tqh_first + while $_x_dump_pnodes_var_pno + x_dump_pnode $_x_dump_pnodes_var_pno + set $_x_dump_pnodes_var_pno = \ + $_x_dump_pnodes_var_pno->p_nodes.tqe_next + end +end + +br _sysio_unmount_all +run -r /tmp/lee foo bar +x_dump_pnodes diff --git a/libsysio/misc/init-env.sh b/libsysio/misc/init-env.sh new file mode 100644 index 0000000..167f421 --- /dev/null +++ b/libsysio/misc/init-env.sh @@ -0,0 +1,38 @@ +# +# Source this file. It will craft a usable name space for your testing. +# +# Lee; Sun Feb 8 18:02:16 EST 2004 +# +# Note: We really should support symlinks someday. +# +unset _root_flags +unset _extras +if [ "x${SYSIO_AUTOMOUNT}" == "xyes" ]; then + _root_flags="2" + # + # Add a /auto directory for automounted file systems. We + # craft one automount that mounts /usr/home from the native + # file system. Further automounts in the sub-mounts are not enabled. + # + _extras=" \ + {mnt, dev=\"incore:0755+0+0\",dir=\"/mnt\",fl=2} \ + {creat, ft=dir,nm=\"/mnt/home\",pm=04755,ow=0,gr=0} \ + {creat, ft=file,nm=\"/mnt/home/.mount\",pm=0600, \ + str=\"native:/home\"} \ + " +fi +export SYSIO_NAMESPACE="\ + {mnt, dev=\"native:/\",dir=/,fl=${_root_flags:-0}} \ + {mnt, dev=\"incore:0755+0+0\",dir=\"/dev\"} \ + {creat, ft=chr,nm=\"/dev/stdin\",pm=0400,mm=0+0} \ + {creat, ft=chr,nm=\"/dev/stdout\",pm=0200,mm=0+1} \ + {creat, ft=chr,nm=\"/dev/stderr\",pm=0200,mm=0+2} \ + {creat, ft=dir,nm=\"/dev/fd\",pm=0755,ow=0,gr=0} \ + {creat, ft=chr,nm=\"/dev/fd/0\",pm=0400,mm=0+0} \ + {creat, ft=chr,nm=\"/dev/fd/1\",pm=0200,mm=0+1} \ + {creat, ft=chr,nm=\"/dev/fd/2\",pm=0200,mm=0+2} \ + {cd, dir=\"$HOME\"} \ + ${_extras} \ +" +unset _root_flags +unset _extras diff --git a/libsysio/src/access.c b/libsysio/src/access.c new file mode 100644 index 0000000..e2f6211 --- /dev/null +++ b/libsysio/src/access.c @@ -0,0 +1,123 @@ +/* + * This Cplant(TM) source code is the property of Sandia National + * Laboratories. + * + * This Cplant(TM) source code is copyrighted by Sandia National + * Laboratories. + * + * The redistribution of this Cplant(TM) source code is subject to the + * terms of the GNU Lesser General Public License + * (see cit/LGPL or http://www.gnu.org/licenses/lgpl.html) + * + * Cplant(TM) Copyright 1998-2003 Sandia Corporation. + * Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive + * license for use of this work by or on behalf of the US Government. + * Export of this program may require a license from the United States + * Government. + */ + +/* + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Questions or comments about this library should be sent to: + * + * Lee Ward + * Sandia National Laboratories, New Mexico + * P.O. Box 5800 + * Albuquerque, NM 87185-1110 + * + * lee@sandia.gov + */ + +#include +#include +#include +#include +#include + +#include "sysio-symbols.h" +#include "sysio.h" + +int +SYSIO_INTERFACE_NAME(access)(const char *path, int amode) +{ + gid_t *list, *entry; + size_t n; + int err = 0; + unsigned mask, mode; + struct stat stbuf; + SYSIO_INTERFACE_DISPLAY_BLOCK; + + SYSIO_INTERFACE_ENTER; + err = 0; + + n = getgroups(0, NULL); + list = NULL; + if (n) { + list = malloc(n * sizeof(gid_t)); + if (!list) { + err = -ENOMEM; + goto out; + } + } + err = getgroups(n, list); + if (err != (int ) n) + goto out; + + err = SYSIO_INTERFACE_NAME(stat)(path, &stbuf); + if (err) { + err = -errno; + goto out; + } + + mask = 0; + if (amode & R_OK) + mask |= S_IRUSR; + if (amode & W_OK) + mask |= S_IWUSR; + if (amode & X_OK) + mask |= S_IXUSR; + + mode = stbuf.st_mode; + if (stbuf.st_uid == getuid() && (mode & mask) == mask) + goto out; + + mask >>= 3; + if (stbuf.st_gid == getgid() && (mode & mask) == mask) + goto out; + + entry = list; + while (n--) + if (stbuf.st_gid == *entry++ && (mode & mask) == mask) + goto out; + + mask >>= 3; + if ((mode & mask) == mask) + goto out; + + err = -EACCES; + +out: + if (list) + free(list); + + SYSIO_INTERFACE_RETURN(err ? -1 : 0, err); +} + +#ifdef REDSTORM +#undef __access +sysio_sym_weak_alias(SYSIO_INTERFACE_NAME(access), + PREPEND(__, SYSIO_INTERFACE_NAME(access))) +#endif diff --git a/libsysio/src/chdir.c b/libsysio/src/chdir.c new file mode 100644 index 0000000..36c4757 --- /dev/null +++ b/libsysio/src/chdir.c @@ -0,0 +1,256 @@ +/* + * This Cplant(TM) source code is the property of Sandia National + * Laboratories. + * + * This Cplant(TM) source code is copyrighted by Sandia National + * Laboratories. + * + * The redistribution of this Cplant(TM) source code is subject to the + * terms of the GNU Lesser General Public License + * (see cit/LGPL or http://www.gnu.org/licenses/lgpl.html) + * + * Cplant(TM) Copyright 1998-2003 Sandia Corporation. + * Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive + * license for use of this work by or on behalf of the US Government. + * Export of this program may require a license from the United States + * Government. + */ + +/* + * ############################################################################# + * # + * # This Cplant(TM) source code is the property of Sandia National + * # Laboratories. + * # + * # This Cplant(TM) source code is copyrighted by Sandia National + * # Laboratories. + * # + * # The redistribution of this Cplant(TM) source code is subject to the + * # terms of the GNU Lesser General Public License + * # (see cit/LGPL or http://www.gnu.org/licenses/lgpl.html) + * # + * # Cplant(TM) Copyright 1998-2003 Sandia Corporation. + * # Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive + * # license for use of this work by or on behalf of the US Government. + * # Export of this program may require a license from the United States + * # Government. + * # + * ############################################################################# + */ + +/* + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Questions or comments about this library should be sent to: + * + * Lee Ward + * Sandia National Laboratories, New Mexico + * P.O. Box 5800 + * Albuquerque, NM 87185-1110 + * + * lee@sandia.gov + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "sysio.h" +#include "inode.h" +#include "mount.h" +#include "file.h" +#include "sysio-symbols.h" + +struct pnode *_sysio_cwd = NULL; + +/* + * Change to directory specified by the given pnode. + */ +int +_sysio_p_chdir(struct pnode *pno) +{ + int err; + + /* + * Revalidate the pnode, and ensure it's a directory + */ + err = _sysio_p_validate(pno, NULL, NULL); + if (err) + return err; + + if (!(pno->p_base->pb_ino && + S_ISDIR(pno->p_base->pb_ino->i_mode))) + return -ENOTDIR; + /* + * Release old if set. + */ + if (_sysio_cwd) + P_RELE(_sysio_cwd); + + /* + * Finally, change to the new. + */ + _sysio_cwd = pno; + + return 0; +} + +int +SYSIO_INTERFACE_NAME(chdir)(const char *path) +{ + int err; + struct pnode *pno; + SYSIO_INTERFACE_DISPLAY_BLOCK; + + SYSIO_INTERFACE_ENTER; + err = _sysio_namei(_sysio_cwd, path, 0, NULL, &pno); + if (err) + SYSIO_INTERFACE_RETURN(-1, err); + + err = _sysio_p_chdir(pno); + if (err) + P_RELE(pno); + SYSIO_INTERFACE_RETURN(err ? -1 : 0, err); +} + +#ifdef REDSTORM +#undef __chdir +sysio_sym_weak_alias(SYSIO_INTERFACE_NAME(chdir), + PREPEND(__, SYSIO_INTERFACE_NAME(chdir))) +#endif + +/* + * Return path tracked by the path ancestor chain. + * + * If the buf pointer is NULL, a buffer large enough to hold the path + * is allocated from the heap. + */ + +static int +_sysio_p_path(struct pnode *pno, char **buf, size_t size) +{ + struct pnode *cur; + size_t len; + size_t n; + char *cp; + + cur = pno; + + /* + * Walk up the tree to the root, summing the component name + * lengths and counting the vertices. + */ + len = 0; + n = 0; + do { + /* + * If this is a covering path-node then the name should be + * the *covered* nodes name, not this one unless we are at + * the root of the name-space. + */ + while (pno == pno->p_mount->mnt_root && pno != pno->p_parent ) + pno = pno->p_mount->mnt_covers; + + /* + * Add length of this component to running sum and + * account for this vertex. + */ + assert((len >= pno->p_base->pb_name.len && + (size_t )~0 - pno->p_base->pb_name.len > len) || + (size_t )~0 - len > pno->p_base->pb_name.len); + len += pno->p_base->pb_name.len; + n++; + assert(n); + pno = pno->p_parent; + } while (pno != pno->p_parent); + + if (!*buf) + size = len + n + 1; + if (len >= size || n >= size - len) + return -ERANGE; + if (!*buf) { + /* + * Allocate path buffer from the heap. + */ + *buf = malloc(size * sizeof(char)); + if (!*buf) + return -ENOMEM; + } + + /* + * Fill in the path buffer. + */ + pno = cur; + cp = *buf + len + n; + *cp = '\0'; /* NUL terminate */ + do { + /* + * If this is a covering path-node then the name should be + * the *covered* nodes name, not this one unless we are at + * the root of the name-space. + */ + while (pno == pno->p_mount->mnt_root && pno != pno->p_parent ) + pno = pno->p_mount->mnt_covers; + + /* + * Add component and separator. + */ + cp -= pno->p_base->pb_name.len; + (void )memcpy(cp, pno->p_base->pb_name.name, + pno->p_base->pb_name.len); + + *--cp = PATH_SEPARATOR; + pno = pno->p_parent; + } while (pno != pno->p_parent); + + return 0; +} + +char * +SYSIO_INTERFACE_NAME(getcwd)(char *buf, size_t size) +{ + int err; + SYSIO_INTERFACE_DISPLAY_BLOCK; + + SYSIO_INTERFACE_ENTER; + err = _sysio_p_path(_sysio_cwd, &buf, buf ? size : 0); + SYSIO_INTERFACE_RETURN(err ? NULL : buf, err); +} + +#ifdef __GLIBC__ +#undef __getcwd +sysio_sym_weak_alias(SYSIO_INTERFACE_NAME(getcwd), + PREPEND(__, SYSIO_INTERFACE_NAME(getcwd))) +#endif + +#if defined(PATH_MAX) && !(defined(REDSTORM)) +char * +SYSIO_INTERFACE_NAME(getwd)(char *buf) +{ + + if (!buf) { + errno = EFAULT; + return NULL; + } + + return SYSIO_INTERFACE_NAME(getcwd)(buf, PATH_MAX); +} +#endif diff --git a/libsysio/src/chmod.c b/libsysio/src/chmod.c new file mode 100644 index 0000000..936dec4 --- /dev/null +++ b/libsysio/src/chmod.c @@ -0,0 +1,118 @@ +/* + * This Cplant(TM) source code is the property of Sandia National + * Laboratories. + * + * This Cplant(TM) source code is copyrighted by Sandia National + * Laboratories. + * + * The redistribution of this Cplant(TM) source code is subject to the + * terms of the GNU Lesser General Public License + * (see cit/LGPL or http://www.gnu.org/licenses/lgpl.html) + * + * Cplant(TM) Copyright 1998-2003 Sandia Corporation. + * Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive + * license for use of this work by or on behalf of the US Government. + * Export of this program may require a license from the United States + * Government. + */ + +/* + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Questions or comments about this library should be sent to: + * + * Lee Ward + * Sandia National Laboratories, New Mexico + * P.O. Box 5800 + * Albuquerque, NM 87185-1110 + * + * lee@sandia.gov + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "sysio.h" +#include "inode.h" +#include "file.h" +#include "sysio-symbols.h" + +static int +do_chmod(struct pnode *pno, struct inode *ino, mode_t mode) +{ + int err; + struct intnl_stat stbuf; + unsigned mask; + + (void )memset(&stbuf, 0, sizeof(struct intnl_stat)); + stbuf.st_mode = mode & 07777; + mask = SETATTR_MODE; + err = _sysio_setattr(pno, ino, mask, &stbuf); + return err; +} + +int +SYSIO_INTERFACE_NAME(chmod)(const char *path, mode_t mode) +{ + int err; + struct pnode *pno; + SYSIO_INTERFACE_DISPLAY_BLOCK; + + SYSIO_INTERFACE_ENTER; + err = _sysio_namei(_sysio_cwd, path, 0, NULL, &pno); + if (err) + goto out; + err = do_chmod(pno, pno->p_base->pb_ino, mode); + P_RELE(pno); +out: + SYSIO_INTERFACE_RETURN(err ? -1 : 0, err); +} + +#ifdef REDSTORM +#undef __chmod +sysio_sym_weak_alias(SYSIO_INTERFACE_NAME(chmod), + PREPEND(__, SYSIO_INTERFACE_NAME(chmod))) +#endif + +int +SYSIO_INTERFACE_NAME(fchmod)(int fd, mode_t mode) +{ + int err; + struct file *fil; + SYSIO_INTERFACE_DISPLAY_BLOCK; + + SYSIO_INTERFACE_ENTER; + err = 0; + fil = _sysio_fd_find(fd); + if (!fil) { + err = -EBADF; + goto out; + } + + err = do_chmod(NULL, fil->f_ino, mode); +out: + SYSIO_INTERFACE_RETURN(err ? -1 : 0, err); +} + +#ifdef REDSTORM +#undef __fchmod +sysio_sym_weak_alias(SYSIO_INTERFACE_NAME(fchmod), + PREPEND(__, SYSIO_INTERFACE_NAME(fchmod))) +#endif diff --git a/libsysio/src/chown.c b/libsysio/src/chown.c new file mode 100644 index 0000000..827a815 --- /dev/null +++ b/libsysio/src/chown.c @@ -0,0 +1,127 @@ +/* + * This Cplant(TM) source code is the property of Sandia National + * Laboratories. + * + * This Cplant(TM) source code is copyrighted by Sandia National + * Laboratories. + * + * The redistribution of this Cplant(TM) source code is subject to the + * terms of the GNU Lesser General Public License + * (see cit/LGPL or http://www.gnu.org/licenses/lgpl.html) + * + * Cplant(TM) Copyright 1998-2003 Sandia Corporation. + * Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive + * license for use of this work by or on behalf of the US Government. + * Export of this program may require a license from the United States + * Government. + */ + +/* + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Questions or comments about this library should be sent to: + * + * Lee Ward + * Sandia National Laboratories, New Mexico + * P.O. Box 5800 + * Albuquerque, NM 87185-1110 + * + * lee@sandia.gov + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "sysio.h" +#include "inode.h" +#include "file.h" +#include "sysio-symbols.h" + +static int +_do_chown(struct pnode *pno, struct inode *ino, uid_t owner, gid_t group) +{ + int err; + struct intnl_stat stbuf; + unsigned mask; + + (void )memset(&stbuf, 0, sizeof(struct intnl_stat)); + mask = 0; + if (owner != (uid_t )-1) { + stbuf.st_uid = owner; + mask |= SETATTR_UID; + } + if (group != (gid_t )-1) { + stbuf.st_gid = group; + mask |= SETATTR_GID; + } + err = _sysio_setattr(pno, ino, mask, &stbuf); + return err; +} + +int +SYSIO_INTERFACE_NAME(chown)(const char *path, uid_t owner, gid_t group) +{ + int err; + struct pnode *pno; + SYSIO_INTERFACE_DISPLAY_BLOCK; + + SYSIO_INTERFACE_ENTER; + err = _sysio_namei(_sysio_cwd, path, 0, NULL, &pno); + if (err) + goto out; + + err = _do_chown(pno, pno->p_base->pb_ino, owner, group); + P_RELE(pno); +out: + SYSIO_INTERFACE_RETURN(err ? -1 : 0, err); +} + +#ifdef REDSTORM +#undef __chown +sysio_sym_weak_alias(SYSIO_INTERFACE_NAME(chown), + PREPEND(__, SYSIO_INTERFACE_NAME(chown))) +#endif + +int +SYSIO_INTERFACE_NAME(fchown)(int fd, uid_t owner, gid_t group) +{ + int err; + struct file *fil; + SYSIO_INTERFACE_DISPLAY_BLOCK; + + SYSIO_INTERFACE_ENTER; + err = 0; + fil = _sysio_fd_find(fd); + if (!fil) { + err = -EBADF; + goto out; + } + + err = _do_chown(NULL, fil->f_ino, owner, group); +out: + SYSIO_INTERFACE_RETURN(err ? -1 : 0, err); +} + +#ifdef REDSTORM +#undef __fchown +sysio_sym_weak_alias(SYSIO_INTERFACE_NAME(fchown), + PREPEND(__, SYSIO_INTERFACE_NAME(fchown))) +#endif + diff --git a/libsysio/src/dev.c b/libsysio/src/dev.c new file mode 100644 index 0000000..046e35f --- /dev/null +++ b/libsysio/src/dev.c @@ -0,0 +1,172 @@ +/* + * This Cplant(TM) source code is the property of Sandia National + * Laboratories. + * + * This Cplant(TM) source code is copyrighted by Sandia National + * Laboratories. + * + * The redistribution of this Cplant(TM) source code is subject to the + * terms of the GNU Lesser General Public License + * (see cit/LGPL or http://www.gnu.org/licenses/lgpl.html) + * + * Cplant(TM) Copyright 1998-2003 Sandia Corporation. + * Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive + * license for use of this work by or on behalf of the US Government. + * Export of this program may require a license from the United States + * Government. + */ + +/* + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Questions or comments about this library should be sent to: + * + * Lee Ward + * Sandia National Laboratories, New Mexico + * P.O. Box 5800 + * Albuquerque, NM 87185-1110 + * + * lee@sandia.gov + */ + +#include +#include +#include +#include +#include +#include + +#include "sysio.h" +#include "inode.h" +#include "dev.h" + +const struct inode_ops _sysio_nodev_ops = { + _sysio_nodev_inop_lookup, + _sysio_nodev_inop_getattr, + _sysio_nodev_inop_setattr, + _sysio_nodev_getdirentries, + _sysio_nodev_inop_mkdir, + _sysio_nodev_inop_rmdir, + _sysio_nodev_inop_symlink, + _sysio_nodev_inop_readlink, + _sysio_nodev_inop_open, + _sysio_nodev_inop_close, + _sysio_nodev_inop_link, + _sysio_nodev_inop_unlink, + _sysio_nodev_inop_rename, + _sysio_nodev_inop_read, + _sysio_nodev_inop_write, + _sysio_nodev_inop_pos, + _sysio_nodev_inop_iodone, + _sysio_nodev_inop_fcntl, + _sysio_nodev_inop_sync, + _sysio_nodev_inop_datasync, + _sysio_nodev_inop_ioctl, + _sysio_nodev_inop_mknod, +#ifdef _HAVE_STATVFS + _sysio_nodev_inop_statvfs, +#endif + _sysio_nodev_inop_gone +}; + +/* + * Support for pseudo-devices. + */ + +struct device { + const char *dev_name; + struct inode_ops dev_ops; +}; + +static struct device cdev[128]; + +int +_sysio_dev_init() +{ + unsigned major; + + major = 0; + do { + cdev[major].dev_name = NULL; + cdev[major].dev_ops = _sysio_nodev_ops; + } while (++major < sizeof(cdev) / sizeof(struct device)); + + return 0; +} + +/* + * Allocate major dev number in the dynamic range [128-255]. + */ +dev_t +_sysio_dev_alloc() +{ + unsigned short major; + static unsigned char c_major = 128; + + assert(c_major); + major = c_major++; + return SYSIO_MKDEV(major, 0); +} + +static int +dev_register(struct device devtbl[], + int major, + const char *name, + struct inode_ops *ops) +{ + + assert(major < 128); + + if (major < 0) { + major = sizeof(cdev) / sizeof(struct device); + while (major--) { + if (!devtbl[major].dev_name) + break; + } + } + if (major < 0) + return -ENXIO; /* I dunno, what? */ + if (devtbl[major].dev_name) + return -EEXIST; + devtbl[major].dev_name = name; + devtbl[major].dev_ops = *ops; + + return major; +} + +int +_sysio_char_dev_register(int major, const char *name, struct inode_ops *ops) +{ + + return dev_register(cdev, major, name, ops); +} + +struct inode_ops * +_sysio_dev_lookup(mode_t mode, dev_t dev) +{ + struct device *devtbl; + dev_t major; + + if (S_ISCHR(mode) || S_ISFIFO(mode)) + devtbl = cdev; + else + return (struct inode_ops *)&_sysio_nodev_ops; + + major = SYSIO_MAJOR_DEV(dev); + if (!(major < 128) || !devtbl[major].dev_name) + return (struct inode_ops *)&_sysio_nodev_ops; + + return &devtbl[major].dev_ops; +} diff --git a/libsysio/src/dup.c b/libsysio/src/dup.c new file mode 100644 index 0000000..9226a5a --- /dev/null +++ b/libsysio/src/dup.c @@ -0,0 +1,97 @@ +/* + * This Cplant(TM) source code is the property of Sandia National + * Laboratories. + * + * This Cplant(TM) source code is copyrighted by Sandia National + * Laboratories. + * + * The redistribution of this Cplant(TM) source code is subject to the + * terms of the GNU Lesser General Public License + * (see cit/LGPL or http://www.gnu.org/licenses/lgpl.html) + * + * Cplant(TM) Copyright 1998-2003 Sandia Corporation. + * Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive + * license for use of this work by or on behalf of the US Government. + * Export of this program may require a license from the United States + * Government. + */ + +/* + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Questions or comments about this library should be sent to: + * + * Lee Ward + * Sandia National Laboratories, New Mexico + * P.O. Box 5800 + * Albuquerque, NM 87185-1110 + * + * lee@sandia.gov + */ + +#include +#include +#include +#include + +#include "sysio.h" +#include "file.h" +#include "sysio-symbols.h" + +int +SYSIO_INTERFACE_NAME(dup2)(int oldfd, int newfd) +{ + int fd; + SYSIO_INTERFACE_DISPLAY_BLOCK; + + SYSIO_INTERFACE_ENTER; + if (newfd < 0) + SYSIO_INTERFACE_RETURN(-1, -EBADF); + + if (oldfd == newfd) { + struct file *fil; + + fil = _sysio_fd_find(oldfd); + if (!(fil && fil->f_ino)) + SYSIO_INTERFACE_RETURN(-1, -EBADF); + SYSIO_INTERFACE_RETURN(newfd, 0); + } + + fd = _sysio_fd_dup2(oldfd, newfd); + SYSIO_INTERFACE_RETURN(fd < 0 ? -1 : fd, fd < 0 ? fd : 0); +} + +#ifdef REDSTORM +#undef __dup2 +sysio_sym_weak_alias(SYSIO_INTERFACE_NAME(dup2), + PREPEND(__, SYSIO_INTERFACE_NAME(dup2))) +#endif + +int +SYSIO_INTERFACE_NAME(dup)(int oldfd) +{ + int fd; + SYSIO_INTERFACE_DISPLAY_BLOCK; + + SYSIO_INTERFACE_ENTER; + fd = _sysio_fd_dup2(oldfd, -1); + SYSIO_INTERFACE_RETURN(fd < 0 ? -1 : fd, fd < 0 ? fd : 0); +} + +#ifdef __GLIBC__ +#undef __dup +sysio_sym_weak_alias(SYSIO_INTERFACE_NAME(dup), + PREPEND(__, SYSIO_INTERFACE_NAME(dup))) +#endif diff --git a/libsysio/src/fcntl.c b/libsysio/src/fcntl.c new file mode 100644 index 0000000..63fb920 --- /dev/null +++ b/libsysio/src/fcntl.c @@ -0,0 +1,148 @@ +/* + * This Cplant(TM) source code is the property of Sandia National + * Laboratories. + * + * This Cplant(TM) source code is copyrighted by Sandia National + * Laboratories. + * + * The redistribution of this Cplant(TM) source code is subject to the + * terms of the GNU Lesser General Public License + * (see cit/LGPL or http://www.gnu.org/licenses/lgpl.html) + * + * Cplant(TM) Copyright 1998-2003 Sandia Corporation. + * Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive + * license for use of this work by or on behalf of the US Government. + * Export of this program may require a license from the United States + * Government. + */ + +/* + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Questions or comments about this library should be sent to: + * + * Lee Ward + * Sandia National Laboratories, New Mexico + * P.O. Box 5800 + * Albuquerque, NM 87185-1110 + * + * lee@sandia.gov + */ + +#include +#include +#include +#include +#include + +#include "sysio.h" +#include "inode.h" +#include "file.h" + +#include "sysio-symbols.h" + +#ifdef HAVE_LUSTRE_HACK +#include + +static int +_sysio_fcntl(int fd, int cmd, va_list ap) +{ + int err; + long arg; + + switch (cmd) { + case F_GETFD: + case F_GETFL: + case F_GETOWN: + return syscall(SYS_fcntl, fd, cmd); + case F_DUPFD: + case F_SETFD: + case F_SETFL: + case F_GETLK: + case F_SETLK: + case F_SETLKW: + case F_SETOWN: + arg = va_arg(ap, long); + return syscall(SYS_fcntl, fd, cmd, arg); + } + + errno = ENOSYS; + return -1; +} +#endif + +int +SYSIO_INTERFACE_NAME(fcntl)(int fd, int cmd, ...) +{ + int err; + struct file *fil; + va_list ap; + SYSIO_INTERFACE_DISPLAY_BLOCK; + + SYSIO_INTERFACE_ENTER; + err = 0; + fil = _sysio_fd_find(fd); + if (!fil) { +#ifdef HAVE_LUSTRE_HACK + va_start(ap, cmd); + err = _sysio_fcntl(fd, cmd, ap); + va_end(ap); + if (err == -1) + err = -errno; + goto out; +#else + err = -EBADF; + goto out; +#endif + } + + switch (cmd) { + + case F_DUPFD: + { + long newfd; + + va_start(ap, cmd); + newfd = va_arg(ap, long); + va_end(ap); + if (newfd != (int )newfd || newfd < 0) { + err = -EBADF; + goto out; + } + err = _sysio_fd_dup2(fd, (int )newfd); + } + break; + default: + va_start(ap, cmd); + err = fil->f_ino->i_ops.inop_fcntl(fil->f_ino, cmd, ap); + va_end(ap); + break; + } + +out: + SYSIO_INTERFACE_RETURN(err ? -1 : 0, err); +} + +#ifdef __GLIBC__ +#undef __fcntl +sysio_sym_weak_alias(SYSIO_INTERFACE_NAME(fcntl), + PREPEND(__, SYSIO_INTERFACE_NAME(fcntl))) +#endif + +#ifdef BSD +#undef _fcntl +sysio_sym_weak_alias(SYSIO_INTERFACE_NAME(fcntl), + PREPEND(_, SYSIO_INTERFACE_NAME(fcntl))) +#endif diff --git a/libsysio/src/file.c b/libsysio/src/file.c new file mode 100644 index 0000000..8d2c3a8 --- /dev/null +++ b/libsysio/src/file.c @@ -0,0 +1,309 @@ +/* + * This Cplant(TM) source code is the property of Sandia National + * Laboratories. + * + * This Cplant(TM) source code is copyrighted by Sandia National + * Laboratories. + * + * The redistribution of this Cplant(TM) source code is subject to the + * terms of the GNU Lesser General Public License + * (see cit/LGPL or http://www.gnu.org/licenses/lgpl.html) + * + * Cplant(TM) Copyright 1998-2003 Sandia Corporation. + * Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive + * license for use of this work by or on behalf of the US Government. + * Export of this program may require a license from the United States + * Government. + */ + +/* + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Questions or comments about this library should be sent to: + * + * Lee Ward + * Sandia National Laboratories, New Mexico + * P.O. Box 5800 + * Albuquerque, NM 87185-1110 + * + * lee@sandia.gov + */ + +#include +#include +#include +#include +#include + +#include "sysio.h" +#include "file.h" +#include "inode.h" +#include "xtio.h" + +/* + * Support for file IO. + */ + +/* + * The open files table and it's size. + */ +static struct file **_sysio_oftab = NULL; +static size_t _sysio_oftab_size = 0; + +/* + * Create and initialize open file record. + */ +struct file * +_sysio_fnew(struct inode *ino, int flags) +{ + struct file *fil; + + fil = malloc(sizeof(struct file)); + if (!fil) + return NULL; + + _SYSIO_FINIT(fil, ino, flags); + I_REF(ino); + + return fil; +} + +/* + * Destroy open file record. + */ +void +_sysio_fgone(struct file *fil) +{ + int err; + + assert(!fil->f_ref); + assert(fil->f_ino); + err = (*fil->f_ino->i_ops.inop_close)(fil->f_ino); + assert(!err); + free(fil); +} + +/* + * IO operation completion handler. + */ +void +_sysio_fcompletio(struct ioctx *ioctx, struct file *fil) +{ + _SYSIO_OFF_T off; + + if (ioctx->ioctx_cc <= 0) + return; + + assert(ioctx->ioctx_ino == fil->f_ino); + off = fil->f_pos + ioctx->ioctx_cc; + if (fil->f_pos && off <= fil->f_pos) + abort(); + fil->f_pos = off; +} + +/* + * Grow (or truncate) the file descriptor table. + */ +static int +fd_grow(size_t n) +{ + int fd; + size_t count; + struct file **noftab, **filp; + + /* + * Sanity check the new size. + */ + fd = (int )n; + if ((size_t )fd != n) + return -EMFILE; + + if (n < 8) + n = 8; + if (n >= _sysio_oftab_size && n - _sysio_oftab_size < _sysio_oftab_size) + n = (n + 1) * 2; + noftab = realloc(_sysio_oftab, n * sizeof(struct file *)); + if (!noftab) + return -ENOMEM; + _sysio_oftab = noftab; + count = _sysio_oftab_size; + _sysio_oftab_size = n; + if (n < count) + return 0; + filp = _sysio_oftab + count; + n -= count; + while (n--) + *filp++ = NULL; + return 0; +} + +#if ZERO_SUM_MEMORY +void +_sysio_fd_shutdown() +{ + + free(_sysio_oftab); + _sysio_oftab_size = 0; +} +#endif + +/* + * Find a free slot in the open files table. + */ +static int +find_free_fildes() +{ + size_t n; + int err; + struct file **filp; + + for (n = 0, filp = _sysio_oftab; + n < _sysio_oftab_size && *filp; + n++, filp++) + ; + if (n >= _sysio_oftab_size) { + err = fd_grow(n); + if (err) + return err; + filp = &_sysio_oftab[n]; + assert(!*filp); + } + + return n; +} + +/* + * Find open file record from file descriptor. + */ +struct file * +_sysio_fd_find(int fd) +{ + if (fd < 0 || (unsigned )fd >= _sysio_oftab_size) + return NULL; + + return _sysio_oftab[fd]; +} + +/* + * Close an open descriptor. + */ +int +_sysio_fd_close(int fd) +{ + struct file *fil; + + fil = _sysio_fd_find(fd); + if (!fil) + return -EBADF; + + _sysio_oftab[fd] = NULL; + + F_RELE(fil); + + return 0; +} + +/* + * Associate open file record with given file descriptor or any available + * file descriptor if less than zero. + */ +int +_sysio_fd_set(struct file *fil, int fd) +{ + int err; + struct file *ofil; + + /* + * New fd < 0 => any available descriptor. + */ + if (fd < 0) { + fd = find_free_fildes(); + if (fd < 0) + return fd; + } + + if ((unsigned )fd >= _sysio_oftab_size) { + err = fd_grow(fd); + if (err) + return err; + } + + /* + * Remember old. + */ + ofil = _sysio_fd_find(fd); + /* + * Take the entry. + */ + _sysio_oftab[fd] = fil; + if (ofil) + F_RELE(ofil); + + return fd; +} + +/* + * Duplicate old file descriptor. + * + * If the new file descriptor is less than zero, the new file descriptor + * is chosen freely. + */ +int +_sysio_fd_dup2(int oldfd, int newfd) +{ + struct file *fil; + int fd; + + if (oldfd == newfd) + return 0; + + fil = _sysio_fd_find(oldfd); + if (!fil) + return -EBADF; + + fd = _sysio_fd_set(fil, newfd); + if (fd >= 0) + F_REF(fil); + return fd; +} + +int +_sysio_fd_close_all() +{ + int fd; + struct file **filp; + + /* + * Close all open descriptors. + */ + for (fd = 0, filp = _sysio_oftab; + (size_t )fd < _sysio_oftab_size; + fd++, filp++) { + if (!*filp) + continue; + F_RELE(*filp); + *filp = NULL; + } + + /* + * Release current working directory. + */ + if (_sysio_cwd) { + P_RELE(_sysio_cwd); + _sysio_cwd = NULL; + } + + return 0; +} diff --git a/libsysio/src/file_hack.c b/libsysio/src/file_hack.c new file mode 100644 index 0000000..bad70be --- /dev/null +++ b/libsysio/src/file_hack.c @@ -0,0 +1,410 @@ +/* + * This Cplant(TM) source code is the property of Sandia National + * Laboratories. + * + * This Cplant(TM) source code is copyrighted by Sandia National + * Laboratories. + * + * The redistribution of this Cplant(TM) source code is subject to the + * terms of the GNU Lesser General Public License + * (see cit/LGPL or http://www.gnu.org/licenses/lgpl.html) + * + * Cplant(TM) Copyright 1998-2003 Sandia Corporation. + * Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive + * license for use of this work by or on behalf of the US Government. + * Export of this program may require a license from the United States + * Government. + */ + +/* + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Questions or comments about this library should be sent to: + * + * Lee Ward + * Sandia National Laboratories, New Mexico + * P.O. Box 5800 + * Albuquerque, NM 87185-1110 + * + * lee@sandia.gov + */ + +#include +#include +#include +#include +#include +#include + +#include "sysio.h" +#include "file.h" +#include "inode.h" +#include "xtio.h" + +/* + * Support for file IO. + */ + +/* + * The open files table + */ +typedef struct oftab { + struct file **table; /* table array */ + size_t size; /* current table size */ + int offset; /* base fd number */ + int max; /* max size */ +} oftab_t; + +#define OFTAB_NATIVE (0) +#define OFTAB_VIRTUAL (1) + +static oftab_t _sysio_oftab[2] = { + {NULL, 0, 0, 0}, + {NULL, 0, 0, 1024*1024}, +}; + +static int native_max_fds = 0; + +static inline void init_oftab() +{ + if (!native_max_fds) { + native_max_fds = sysconf(_SC_OPEN_MAX); + if (native_max_fds <= 0) + abort(); + _sysio_oftab[OFTAB_NATIVE].max = native_max_fds - 1; + _sysio_oftab[OFTAB_VIRTUAL].offset = native_max_fds; + } +} + +static inline oftab_t *select_oftab(int fd) +{ + return & _sysio_oftab[fd >= native_max_fds || fd < 0]; +} + +/* + * Create and initialize open file record. + */ +struct file * +_sysio_fnew(struct inode *ino, int flags) +{ + struct file *fil; + + fil = malloc(sizeof(struct file)); + if (!fil) + return NULL; + + _SYSIO_FINIT(fil, ino, flags); + I_REF(ino); + + return fil; +} + +/* + * Destroy open file record. + */ +void +_sysio_fgone(struct file *fil) +{ + int err; + + assert(!fil->f_ref); + assert(fil->f_ino); + err = (*fil->f_ino->i_ops.inop_close)(fil->f_ino); + assert(!err); + free(fil); +} + +/* + * IO operation completion handler. + */ +void +_sysio_fcompletio(struct ioctx *ioctx, struct file *fil) +{ + _SYSIO_OFF_T off; + + if (ioctx->ioctx_cc <= 0) + return; + + assert(ioctx->ioctx_ino == fil->f_ino); + off = fil->f_pos + ioctx->ioctx_cc; + if (fil->f_pos && off <= fil->f_pos) + abort(); + fil->f_pos = off; +} + +/* + * Grow (or truncate) the file descriptor table. + */ +static int +fd_grow(oftab_t *oftab, size_t n) +{ + int fd; + size_t count; + struct file **noftab, **filp; + + /* + * Sanity check the new size. + */ + fd = (int )n; + if ((size_t )fd != n) + return -EMFILE; + + n++; /* index -> size */ + assert(n > oftab->size); + + if (n > oftab->max) + return -ERANGE; + + if (n < 8) + n = 8; + if (n - oftab->size < oftab->size) + n = (n + 1) * 2; + noftab = realloc(oftab->table, n * sizeof(struct file *)); + if (!noftab) + return -ENOMEM; + oftab->table = noftab; + count = oftab->size; + oftab->size = n; + if (n < count) + return 0; + filp = oftab->table + count; + n -= count; + while (n--) + *filp++ = NULL; + return 0; +} + +#if ZERO_SUM_MEMORY +static void free_oftab(oftab_t *ot) +{ + if (ot->table) { + free(ot->table); + ot->size = 0; + } +} + +void +_sysio_fd_shutdown() +{ + free_oftab(&_sysio_oftab[OFTAB_NATIVE]); + free_oftab(&_sysio_oftab[OFTAB_VIRTUAL]); +} +#endif + +/* + * Find a free slot in the open files table. + * target < 0: any free slot + * target >= 0: get slot [target] + */ +static int +find_free_fildes(oftab_t *oftab, int target) + { + int n; + int err; + struct file **filp; + + if (target < 0) { + for (n = 0, filp = oftab->table; + n < oftab->size && *filp; + n++, filp++) + ; + } else + n = target - oftab->offset; + + if (n >= oftab->size) { + err = fd_grow(oftab, n); + if (err) + return err; + filp = &oftab->table[n]; + assert(!*filp); + } + +#ifdef HAVE_LUSTRE_HACK + /* FIXME sometimes we could intercept open/socket to create + * a fd, but missing close()? currently we have this problem + * with resolv lib. as a workaround simply destroy the file + * struct here. + */ + if (oftab->table[n]) { + free(oftab->table[n]); + oftab->table[n] = NULL; + } +#endif + + return oftab->offset + n; +} + +/* + * Find open file record from file descriptor. + * clear this entry if 'clear' is non-zero + */ +static struct file * +__sysio_fd_get(int fd, int clear) +{ + oftab_t *oftab; + struct file *file; + + init_oftab(); + + if (fd < 0) + return NULL; + + oftab = select_oftab(fd); + if (!oftab->table || fd >= oftab->offset + oftab->size) + return NULL; + + file = oftab->table[fd - oftab->offset]; + if (clear) + oftab->table[fd - oftab->offset] = NULL; + + return file; +} + +/* + * Find open file record from file descriptor. + */ +struct file * +_sysio_fd_find(int fd) +{ + return __sysio_fd_get(fd, 0); +} + +/* + * Close an open descriptor. + */ +int +_sysio_fd_close(int fd) +{ + struct file *fil; + + fil = fil = __sysio_fd_get(fd, 1); + if (!fil) + return -EBADF; + + F_RELE(fil); + + return 0; +} + +/* + * Associate open file record with given file descriptor or any available + * file descriptor if less than zero. + */ +int +_sysio_fd_set(struct file *fil, int fd) +{ + int err; + struct file *ofil; + oftab_t *oftab; + + init_oftab(); + + oftab = select_oftab(fd); + + /* + * New fd < 0 => any available descriptor. + */ + fd = find_free_fildes(oftab, fd); + if (fd < 0) + return fd; + + assert(fd < oftab->offset + oftab->size); + + /* + * Remember old. + */ + ofil = __sysio_fd_get(fd, 1); + if (ofil) + F_RELE(ofil); + + oftab->table[fd - oftab->offset] = fil; + + return fd; +} + +/* + * Duplicate old file descriptor. + * + * If the new file descriptor is less than zero, the new file descriptor + * is chosen freely. + */ +int +_sysio_fd_dup2(int oldfd, int newfd) +{ + struct file *fil; + int fd; + + init_oftab(); + + if (oldfd == newfd) + return 0; + + fil = _sysio_fd_find(oldfd); + if (!fil) + return -EBADF; + + /* old & new must belong to the same oftab */ + if (select_oftab(oldfd) != select_oftab(newfd)) + return -EINVAL; + + fd = _sysio_fd_set(fil, newfd); + if (fd >= 0) + F_REF(fil); + return fd; +} + +void +_sysio_oftable_close_all(oftab_t *oftab) +{ + struct file **filp; + int fd; + + for (fd = 0, filp = oftab->table; + (size_t )fd < oftab->size; + fd++, filp++) { + if (!*filp) + continue; + F_RELE(*filp); + *filp = NULL; + } +} + +int +_sysio_fd_close_all() +{ + int fd; + struct file **filp; + oftab_t *oftab; + int i; + + /* + * Close all open descriptors. + */ + _sysio_oftable_close_all(&_sysio_oftab[OFTAB_VIRTUAL]); + /* XXX see liblustre/llite_lib.c for explaination */ +#if 0 + _sysio_oftable_close_all(&_sysio_oftab[OFTAB_NATIVE]); +#endif + + /* + * Release current working directory. + */ + if (_sysio_cwd) { + P_RELE(_sysio_cwd); + _sysio_cwd = NULL; + } + + return 0; +} diff --git a/libsysio/src/fs.c b/libsysio/src/fs.c new file mode 100644 index 0000000..29abe4f --- /dev/null +++ b/libsysio/src/fs.c @@ -0,0 +1,161 @@ +/* + * This Cplant(TM) source code is the property of Sandia National + * Laboratories. + * + * This Cplant(TM) source code is copyrighted by Sandia National + * Laboratories. + * + * The redistribution of this Cplant(TM) source code is subject to the + * terms of the GNU Lesser General Public License + * (see cit/LGPL or http://www.gnu.org/licenses/lgpl.html) + * + * Cplant(TM) Copyright 1998-2003 Sandia Corporation. + * Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive + * license for use of this work by or on behalf of the US Government. + * Export of this program may require a license from the United States + * Government. + */ + +/* + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Questions or comments about this library should be sent to: + * + * Lee Ward + * Sandia National Laboratories, New Mexico + * P.O. Box 5800 + * Albuquerque, NM 87185-1110 + * + * lee@sandia.gov + */ + +#include +#include +#include +#include +#include +#include + +#include "sysio.h" +#include "fs.h" +#include "inode.h" + +/* + * File system abstractipon support. + */ + +/* + * The "file system switch". + */ +static LIST_HEAD(, fsswent) fsswitch = { NULL }; + +/* + * Lookup named entry in the switch. + */ +struct fsswent * +_sysio_fssw_lookup(const char *name) +{ + struct fsswent *fssw; + + if (!fsswitch.lh_first) + return NULL; + + fssw = fsswitch.lh_first; + do { + if (strcmp(fssw->fssw_name, name) == 0) + return fssw; + fssw = fssw->fssw_link.le_next; + } while (fssw); + return NULL; +} + +/* + * Register driver. + */ +int +_sysio_fssw_register(const char *name, struct fssw_ops *ops) +{ + struct fsswent *fssw; + + fssw = _sysio_fssw_lookup(name); + if (fssw) + return -EEXIST; + + fssw = malloc(sizeof(struct fsswent) + strlen(name) + 1); + if (!fssw) + return -ENOMEM; + fssw->fssw_name = (char *)fssw + sizeof(struct fsswent); + (void )strcpy((char *)fssw->fssw_name, name); + fssw->fssw_ops = *ops; + + LIST_INSERT_HEAD(&fsswitch, fssw, fssw_link); + + return 0; +} + +#if ZERO_SUM_MEMORY +/* + * Shutdown + */ +void +_sysio_fssw_shutdown() +{ + struct fsswent *fssw; + + while ((fssw = fsswitch.lh_first)) { + LIST_REMOVE(fssw, fssw_link); + free(fssw); + } +} +#endif + +/* + * Allocate and initialize a new file system record. + */ +struct filesys * +_sysio_fs_new(struct filesys_ops *ops, unsigned flags, void *private) +{ + struct filesys *fs; + + fs = malloc(sizeof(struct filesys)); + if (!fs) + return NULL; + FS_INIT(fs, flags, ops, private); + return fs; +} + +/* + * Dispose of given file system record. + */ +void +_sysio_fs_gone(struct filesys *fs) +{ + size_t n; + struct itable_entry *head; + + if (fs->fs_ref) + abort(); + n = FS_ITBLSIZ; + do { + head = &fs->fs_itbl[--n]; + while (head->lh_first) + _sysio_i_gone(head->lh_first); + } while (n); + if (n) + abort(); + + (*fs->fs_ops.fsop_gone)(fs); + free(fs); +} diff --git a/libsysio/src/fsync.c b/libsysio/src/fsync.c new file mode 100644 index 0000000..988cb507 --- /dev/null +++ b/libsysio/src/fsync.c @@ -0,0 +1,81 @@ +/* + * This Cplant(TM) source code is the property of Sandia National + * Laboratories. + * + * This Cplant(TM) source code is copyrighted by Sandia National + * Laboratories. + * + * The redistribution of this Cplant(TM) source code is subject to the + * terms of the GNU Lesser General Public License + * (see cit/LGPL or http://www.gnu.org/licenses/lgpl.html) + * + * Cplant(TM) Copyright 1998-2003 Sandia Corporation. + * Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive + * license for use of this work by or on behalf of the US Government. + * Export of this program may require a license from the United States + * Government. + */ + +/* + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Questions or comments about this library should be sent to: + * + * Lee Ward + * Sandia National Laboratories, New Mexico + * P.O. Box 5800 + * Albuquerque, NM 87185-1110 + * + * lee@sandia.gov + */ + +#include +#include +#include +#include + +#include "sysio.h" +#include "file.h" +#include "inode.h" + +int +SYSIO_INTERFACE_NAME(fsync)(int fd) +{ + struct file *fil; + int err; + SYSIO_INTERFACE_DISPLAY_BLOCK; + + SYSIO_INTERFACE_ENTER; + fil = _sysio_fd_find(fd); + if (!(fil && fil->f_ino)) + SYSIO_INTERFACE_RETURN(-1, -EBADF); + err = (*fil->f_ino->i_ops.inop_sync)(fil->f_ino); + SYSIO_INTERFACE_RETURN(err ? -1 : 0, err); +} + +int +SYSIO_INTERFACE_NAME(fdatasync)(int fd) +{ + struct file *fil; + int err; + SYSIO_INTERFACE_DISPLAY_BLOCK; + + SYSIO_INTERFACE_ENTER; + fil = _sysio_fd_find(fd); + if (!(fil && fil->f_ino)) + SYSIO_INTERFACE_RETURN(-1, -EBADF); + err = (*fil->f_ino->i_ops.inop_datasync)(fil->f_ino); + SYSIO_INTERFACE_RETURN(err ? -1 : 0, err); +} diff --git a/libsysio/src/getdirentries.c b/libsysio/src/getdirentries.c new file mode 100644 index 0000000..7e1a81f --- /dev/null +++ b/libsysio/src/getdirentries.c @@ -0,0 +1,307 @@ +/* + * This Cplant(TM) source code is the property of Sandia National + * Laboratories. + * + * This Cplant(TM) source code is copyrighted by Sandia National + * Laboratories. + * + * The redistribution of this Cplant(TM) source code is subject to the + * terms of the GNU Lesser General Public License + * (see cit/LGPL or http://www.gnu.org/licenses/lgpl.html) + * + * Cplant(TM) Copyright 1998-2004 Sandia Corporation. + * Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive + * license for use of this work by or on behalf of the US Government. + * Export of this program may require a license from the United States + * Government. + */ + +/* + * ############################################################################# + * # + * # This Cplant(TM) source code is the property of Sandia National + * # Laboratories. + * # + * # This Cplant(TM) source code is copyrighted by Sandia National + * # Laboratories. + * # + * # The redistribution of this Cplant(TM) source code is subject to the + * # terms of the GNU Lesser General Public License + * # (see cit/LGPL or http://www.gnu.org/licenses/lgpl.html) + * # + * # Cplant(TM) Copyright 1998-2004 Sandia Corporation. + * # Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive + * # license for use of this work by or on behalf of the US Government. + * # Export of this program may require a license from the United States + * # Government. + * # + * ############################################################################# + */ + +/* + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Questions or comments about this library should be sent to: + * + * Lee Ward + * Sandia National Laboratories, New Mexico + * P.O. Box 5800 + * Albuquerque, NM 87185-1110 + * + * lee@sandia.gov + */ + +#include +#include +#ifdef __GLIBC__ +#include +#endif +#include +#include +#include +#include +#include +#include + +#include "sysio.h" +#include "inode.h" +#include "file.h" +#include "sysio-symbols.h" + +#ifndef __GNUC__ +#define __restrict +#endif + +static ssize_t +PREPEND(_, SYSIO_INTERFACE_NAME(getdirentries64))(int fd, + char *buf, + size_t nbytes, + _SYSIO_OFF_T * __restrict + basep) +{ + struct file *fil; + ssize_t cc; + SYSIO_INTERFACE_DISPLAY_BLOCK; + + SYSIO_INTERFACE_ENTER; + + fil = _sysio_fd_find(fd); + if (!(fil && fil->f_ino)) + SYSIO_INTERFACE_RETURN(-1, -EBADF); + + if (!S_ISDIR(fil->f_ino->i_mode)) + SYSIO_INTERFACE_RETURN(-1, -ENOTDIR); + + cc = + (*fil->f_ino->i_ops.inop_getdirentries)(fil->f_ino, + buf, + nbytes, + basep); + SYSIO_INTERFACE_RETURN(cc < 0 ? -1 : cc, cc < 0 ? (int )cc : 0); +} + +#if _LARGEFILE64_SOURCE +#undef getdirentries64 +sysio_sym_strong_alias(PREPEND(_, SYSIO_INTERFACE_NAME(getdirentries64)), + SYSIO_INTERFACE_NAME(getdirentries64)) +#endif + +#undef getdirentries + +#ifndef DIRENT64_IS_NATURAL + +#ifndef EOVERFLOW +#define EOVERFLOW ERANGE +#endif + +#ifdef _DIRENT_HAVE_D_NAMLEN +#define _namlen(dp) ((dp)->d_namlen) +#else +#define _namlen(dp) (strlen((dp)->d_name)) +#endif + +#ifndef _rndup +#define _rndup(n, boundary) \ + ((((n) + (boundary) - 1 ) / (boundary)) * (boundary)) +#endif + +#ifndef BSD +ssize_t +SYSIO_INTERFACE_NAME(getdirentries)(int fd, + char *buf, + size_t nbytes, + off_t * __restrict basep) +#else +int +SYSIO_INTERFACE_NAME(getdirentries)(int fd, + char *buf, + int nbytes, + long * __restrict basep) +#endif +{ + size_t inbytes; + void *ibuf; + _SYSIO_OFF_T ibase; + ssize_t cc; + struct dirent *dp, *nxtdp; +#if defined(BSD) + int off; +#endif + struct intnl_dirent *od64p, *d64p; + size_t n; + size_t reclen; + char *cp; + SYSIO_INTERFACE_DISPLAY_BLOCK; + +#define _dbaselen ((size_t )&((struct dirent *)0)->d_name[0]) + +#ifdef __GLIBC__ +#define _dreclen(namlen) \ + ((_dbaselen + (namlen) + __alignof__ (struct dirent)) & \ + ~(__alignof__ (struct dirent) - 1)) +#else /* !defined(__GLIBC__) */ +#define _dreclen(namlen) \ + _rndup(_dbaselen + (namlen) + 1, sizeof(int)) +#endif + +#if defined(__GLIBC__) +#define _fast_alloc(n) alloca(n) +#define _fast_free(p) +#else /* !defined(__GLIBC__) */ +#define _fast_alloc(n) malloc(n) +#define _fast_free(p) free(p) +#endif + + SYSIO_INTERFACE_ENTER; +#if defined(BSD) + if (nbytes < 0) + SYSIO_INTERFACE_RETURN(-1, -EINVAL); +#endif + + inbytes = nbytes; + if (inbytes > 8 * 1024) { + /* + * Limit stack use. + */ + inbytes = 8 * 1024; + } + ibuf = _fast_alloc(inbytes); + if (!ibuf) + SYSIO_INTERFACE_RETURN(-1, -ENOMEM); + + dp = (struct dirent *)buf; + + ibase = *basep; + cc = + PREPEND(_, SYSIO_INTERFACE_NAME(getdirentries64))(fd, + ibuf, + inbytes, + &ibase); + if (cc < 0) { + cc = -errno; + goto out; + } + *basep = (off_t )ibase; + if (sizeof(*basep) != sizeof(ibase) && *basep != ibase) { + cc = -EOVERFLOW; + goto out; + } + +#if defined(BSD) + off = *basep; +#endif + od64p = NULL; + d64p = ibuf; + for (;;) { + if (!cc) + break; +#ifdef HAVE_D_NAMLEN + n = d64p->d_namlen; +#else + n = strlen(d64p->d_name); +#endif + reclen = _dreclen(n); + if (reclen >= (unsigned )nbytes) + break; + dp->d_ino = (ino_t )d64p->d_ino; +#if !(defined(BSD)) + dp->d_off = (off_t )d64p->d_off; +#endif + if ((sizeof(dp->d_ino) != sizeof(d64p->d_ino) && + dp->d_ino != d64p->d_ino) + || +#if !(defined(BSD)) + (sizeof(dp->d_off) != sizeof(d64p->d_off) && + dp->d_off != d64p->d_off) +#else + (off + (int )reclen < off) +#endif + ) { + cc = -EOVERFLOW; + break; + } + dp->d_type = d64p->d_type; + dp->d_reclen = reclen; + nxtdp = (struct dirent *)((char *)dp + dp->d_reclen); + (void )memcpy(dp->d_name, d64p->d_name, n); + for (cp = dp->d_name + n; cp < (char *)nxtdp; *cp++ = '\0') + ; + cc -= d64p->d_reclen; + od64p = d64p; + d64p = (struct dirent64 *)((char *)d64p + d64p->d_reclen); + nbytes -= reclen; +#if defined(BSD) + off += reclen; +#endif + dp = nxtdp; + } + +out: + _fast_free(ibuf); + + if (dp == (struct dirent *)buf && cc < 0) + SYSIO_INTERFACE_RETURN(-1, (int )cc); + cc = (char *)dp - buf; + if (cc) + *basep = +#if !(defined(BSD)) + od64p->d_off; +#else + off; +#endif + SYSIO_INTERFACE_RETURN(cc, 0); + +#ifdef __GLIBC__ +#undef _fast_alloc +#undef _fast_free +#endif +#undef _dreclen +#undef _dbaselen +} +#else /* !defined(DIRENT64_IS_NATURAL) */ +sysio_sym_strong_alias(PREPEND(_, SYSIO_INTERFACE_NAME(getdirentries64), + SYSIO_INTERFACE_NAME(getdirentries))) +#endif + +#ifdef REDSTORM +#undef __getdirentries +sysio_sym_weak_alias(SYSIO_INTERFACE_NAME(getdirentries), + PREPEND(__, SYSIO_INTERFACE_NAME(getdirentries))) +#endif +#if defined(BSD) || defined(REDSTORM) +#undef _getdirentries +sysio_sym_weak_alias(SYSIO_INTERFACE_NAME(getdirentries), + PREPEND(_, SYSIO_INTERFACE_NAME(getdirentries))) +#endif diff --git a/libsysio/src/init.c b/libsysio/src/init.c new file mode 100644 index 0000000..38d0794 --- /dev/null +++ b/libsysio/src/init.c @@ -0,0 +1,625 @@ +/* + * This Cplant(TM) source code is the property of Sandia National + * Laboratories. + * + * This Cplant(TM) source code is copyrighted by Sandia National + * Laboratories. + * + * The redistribution of this Cplant(TM) source code is subject to the + * terms of the GNU Lesser General Public License + * (see cit/LGPL or http://www.gnu.org/licenses/lgpl.html) + * + * Cplant(TM) Copyright 1998-2004 Sandia Corporation. + * Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive + * license for use of this work by or on behalf of the US Government. + * Export of this program may require a license from the United States + * Government. + */ + +/* + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Questions or comments about this library should be sent to: + * + * Lee Ward + * Sandia National Laboratories, New Mexico + * P.O. Box 5800 + * Albuquerque, NM 87185-1110 + * + * lee@sandia.gov + */ + +#define _BSD_SOURCE + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "sysio.h" +#include "inode.h" +#include "fs.h" +#include "mount.h" +#include "file.h" +#include "dev.h" +#include "xtio.h" + +#ifdef STDFD_DEV +#include "stdfd.h" +#endif + +/* + * The namespace assembly buffer passes args with a `name'=`value' + * syntax. We use the following to record that in various + * routines below. + */ +struct named_argument { + const char *name; /* arg name */ + char *value; /* arg value */ +}; + +/* + * White space characters. + */ +#define IGNORE_WHITE " \t\r\n" + +/* + * Sysio library initialization. Must be called before anything else in the + * library. + */ +int +_sysio_init() +{ + int err; +#ifdef WITH_SOCKETS + int _sysio_sockets_init(void); +#endif + + err = _sysio_ioctx_init(); + if (err) + goto error; + err = _sysio_i_init(); + if (err) + goto error; + err = _sysio_mount_init(); + if (err) + goto error; + + err = _sysio_dev_init(); + if (err) + goto error; +#ifdef STDFD_DEV + err = _sysio_stdfd_init(); + if (err) + goto error; +#endif +#ifdef WITH_SOCKETS + err = _sysio_sockets_init(); + if (err) + goto error; +#endif + + goto out; +error: + errno = -err; +out: + /* + * Unlike all other _sysio routines, this one returns with errno + * set. It also returns the error, as usual. + */ + return err; +} + +/* + * Sysio library shutdown. + */ +void +_sysio_shutdown() +{ + + if (!(_sysio_fd_close_all() == 0 && + _sysio_unmount_all() == 0)) + abort(); + +#if ZERO_SUM_MEMORY + _sysio_fd_shutdown(); + _sysio_i_shutdown(); + _sysio_fssw_shutdown(); +#endif +} + +/* + * (kind of)Duplicates strtok function. + * + * Given a buffer, returns the longest string + * that does not contain any delim characters. Will + * remove ws and any characters in the ignore string. + * Returns the token. + * + * The parameter controlling acceptance controls whether a positive + * match for some delimiter be made or not. If set, then either a delimiter + * or NUL character is success. + * + */ +static const char * +get_token(const char *buf, + int accepts, + const char *delim, + const char *ignore, + char *tbuf) +{ + char c; + int escape, quote; + + /* + * Find the first occurance of delim, recording how many + * characters lead up to it. Ignore indicated characters. + */ + escape = quote = 0; + while ((c = *buf) != '\0') { + buf++; + if (!escape) { + if (c == '\\') { + escape = 1; + continue; + } + if (c == '\"') { + quote ^= 1; + continue; + } + if (!quote) { + if (strchr(delim, c) != NULL) { + accepts = 1; + break; + } + if (strchr(ignore, c) != NULL) + continue; + } + } else + escape = 0; + *tbuf++ = c; + } + if (!accepts) + return NULL; + *tbuf = '\0'; /* NUL term */ + return buf; +} + +/* + * Parse and record named arguments given as `name = value', comma-separated + * pairs. + * + * NB: Alters the passed buffer. + */ +static char * +get_args(char *buf, struct named_argument *vec) +{ + char *nxt; + char *name, *value; + struct named_argument *v; + + for (;;) { + nxt = (char *)get_token(buf, 1, "=,", IGNORE_WHITE, name = buf); + if (!nxt || + (nxt != buf && *name == '\0' && buf + strlen(buf) == nxt)) { + buf = NULL; + break; + } + if (*name == '\0') + break; + buf = (char *)get_token(nxt, 1, ",", IGNORE_WHITE, value = nxt); + if (*value == '\0') + value = NULL; + for (v = vec; v->name; v++) + if (strcmp(v->name, name) == 0) + break; + if (!v->name) + return NULL; + v->value = value; + } + + return buf; +} + +static int +parse_mm(const char *s, dev_t *devp) +{ + unsigned long ul; + char *cp; + dev_t dev; + + ul = strtoul(s, &cp, 0); + if (*cp != '+' || ul > USHRT_MAX) + return -EINVAL; + dev = ul << 16; + s = (const char *)++cp; + ul = strtoul(s, &cp, 0); + if (*cp != '\0' || ul > USHRT_MAX) + return -EINVAL; + dev |= ul & 0xffff; + *devp = dev; + return 0; +} + +/* + * Performs the creat command for the namespace assembly + * + * NB: Alters the passed buffer. + */ +static int +do_creat(char *args) +{ + size_t len; + struct named_argument v[] = { + { "ft", NULL }, /* file type */ + { "nm", NULL }, /* name */ + { "pm", NULL }, /* permissions */ + { "ow", NULL }, /* owner */ + { "gr", NULL }, /* group */ + { "mm", NULL }, /* major + minor */ + { "str", NULL }, /* file data */ + { NULL, NULL } + }; + const char *cp; + long perms; + long owner, group; + struct pnode *dir, *pno; + mode_t mode; + struct intent intent; + dev_t dev; + int err; + + len = strlen(args); + if (get_args(args, v) - args != (ssize_t )len || + !(v[0].value && + v[1].value && + v[2].value)) + return -EINVAL; + perms = strtol(v[2].value, (char **)&cp, 0); + if (*cp || + perms < 0 || + (perms == LONG_MAX && errno == ERANGE) || + ((unsigned)perms & ~07777)) + return -EINVAL; + if (v[3].value) { + owner = strtol(v[3].value, (char **)&cp, 0); + if (*cp || + ((owner == LONG_MIN || owner == LONG_MAX) + && errno == ERANGE)) + return -EINVAL; + } else + owner = getuid(); + if (v[4].value) { + group = strtol(v[4].value, (char **)&cp, 0); + if (*cp || + ((group == LONG_MIN || group == LONG_MAX) && + errno == ERANGE)) + return -EINVAL; + } else + group = getegid(); + + if (!(dir = _sysio_cwd) && !(dir = _sysio_root)) + return -ENOENT; + err = 0; + mode = perms; + if (strcmp(v[0].value, "dir") == 0) { + INTENT_INIT(&intent, INT_CREAT, &mode, 0); + err = _sysio_namei(dir, v[1].value, ND_NEGOK, &intent, &pno); + if (err) + return err; + if (pno->p_base->pb_ino) + err = -EEXIST; + else if (IS_RDONLY(pno->p_parent, + pno->p_parent->p_base->pb_ino)) + err = -EROFS; + else { + struct inode *ino; + + ino = pno->p_parent->p_base->pb_ino; + err = (*ino->i_ops.inop_mkdir)(pno, mode); + } + P_RELE(pno); + } else if (strcmp(v[0].value, "chr") == 0) { + if (!(v[5].value && parse_mm(v[5].value, &dev) == 0)) + return -EINVAL; + mode |= S_IFCHR; + INTENT_INIT(&intent, INT_CREAT, &mode, 0); + err = _sysio_namei(dir, v[1].value, ND_NEGOK, &intent, &pno); + if (err) + return err; + if (pno->p_base->pb_ino) + err = -EEXIST; + else if (IS_RDONLY(pno->p_parent, + pno->p_parent->p_base->pb_ino)) + err = -EROFS; + else { + struct inode *ino; + + ino = pno->p_parent->p_base->pb_ino; + err = (*ino->i_ops.inop_mknod)(pno, mode, dev); + } + P_RELE(pno); + } else if (strcmp(v[0].value, "blk") == 0) { + /* + * We don't support block special files yet. + */ + return -EINVAL; + } else if (strcmp(v[0].value, "file") == 0) { + int i; + struct inode *ino; + + i = O_CREAT|O_EXCL; + INTENT_INIT(&intent, INT_CREAT, &mode, &i); + err = _sysio_namei(dir, v[1].value, ND_NEGOK, &intent, &pno); + if (err) + return err; + err = _sysio_open(pno, O_CREAT|O_EXCL, mode); + if (err) { + P_RELE(pno); + return err; + } + ino = pno->p_base->pb_ino; + if (!err && v[6].value) { + struct iovec iovec; + struct intnl_xtvec xtvec; + struct ioctx io_context; + + /* + * Deposit optional file content. + */ + iovec.iov_base = v[6].value; + iovec.iov_len = strlen(v[6].value); + xtvec.xtv_off = 0; + xtvec.xtv_len = iovec.iov_len; + IOCTX_INIT(&io_context, + 1, + (ioid_t )&io_context, + 1, + ino, + &iovec, 1, + &xtvec, 1); + _sysio_ioctx_enter(&io_context); + err = + (*ino->i_ops.inop_write)(pno->p_base->pb_ino, + &io_context); + if (!err) { + ssize_t cc; + + cc = _sysio_ioctx_wait(&io_context); + if (cc < 0) + err = cc; + else if ((size_t )cc != iovec.iov_len) + err = -EIO; /* huh? */ + } else + _sysio_ioctx_complete(&io_context); + } + i = (*ino->i_ops.inop_close)(ino); + if (!err) + err = i; + P_RELE(pno); + } else + err = -EINVAL; + + return err; +} + +/* + * Do mount. + * + * NB: The passed buffer is altered. + */ +static int +do_mnt(char *args) +{ + size_t len; + struct named_argument v[] = { + { "dev", NULL }, /* source (type:dev) */ + { "dir", NULL }, /* target dir */ + { "fl", NULL }, /* flags */ + { "da", NULL }, /* mount data */ + { NULL, NULL } + }; + char *ty, *name; + unsigned long flags; + struct pnode *dir; + + len = strlen(args); + if (get_args(args, v) - args != (ssize_t )len || + !(v[0].value && v[1].value)) + return -EINVAL; + ty = (char *)get_token(v[0].value, 1, ":", "", name = v[0].value); + flags = 0; + if (v[2].value) { + char *cp; + + /* + * Optional flags. + */ + flags = strtoul(v[2].value, &cp, 0); + if (*cp || (flags == ULONG_MAX && errno == ERANGE)) + return -EINVAL; + } + + if (strlen(v[1].value) == 1 && v[1].value[0] == PATH_SEPARATOR) { + /* + * Aha! It's root they want. Have to do that special. + */ + return _sysio_mount_root(ty, name, flags, v[3].value); + } + + if (!(dir = _sysio_cwd) && !(dir = _sysio_root)) + return -ENOENT; + return _sysio_mount(dir, ty, v[1].value, name, flags, v[3].value); +} + + +/* + * Chdir + * + * NB: Alters the passed buffer. + */ +static int +do_cd(char *args) +{ + size_t len; + struct named_argument v[] = { + { "dir", NULL }, /* directory */ + { NULL, NULL } + }; + int err; + struct pnode *dir, *pno; + + len = strlen(args); + if (get_args(args, v) - args != (ssize_t )len || !v[0].value) + return -EINVAL; + + if (!(dir = _sysio_cwd) && !(dir = _sysio_root)) + return -ENOENT; + err = _sysio_namei(dir, v[0].value, 0, NULL, &pno); + if (err) + return err; + err = _sysio_p_chdir(pno); + if (err) + P_RELE(pno); + return err; +} + +/* + * Does a chmod + * + * NB: Alters passed buffer. + */ +static int +do_chmd(char *args) +{ + size_t len; + struct named_argument v[] = { + { "src", NULL }, /* path */ + { "pm", NULL }, /* perms */ + { NULL, NULL } + }; + long perms; + char *cp; + struct intnl_stat stbuf; + int err; + struct pnode *dir, *pno; + + len = strlen(args); + if (get_args(args, v) - args != (ssize_t )len || + !(v[0].value && v[1].value)) + return -EINVAL; + perms = strtol(v[1].value, &cp, 0); + if (*cp || + perms < 0 || + (perms == LONG_MAX && errno == ERANGE) || + ((unsigned)perms & ~07777)) + return -EINVAL; + (void )memset(&stbuf, 0, sizeof(stbuf)); + stbuf.st_mode = (mode_t)perms; + + if (!(dir = _sysio_cwd) && !(dir = _sysio_root)) + return -ENOENT; + err = _sysio_namei(dir, v[0].value, 0, NULL, &pno); + if (err) + return err; + err = _sysio_setattr(pno, pno->p_base->pb_ino, SETATTR_MODE, &stbuf); + P_RELE(pno); + + return err; +} + +/* + * Execute the given cmd. + * + * NB: Buf is altered. + */ +static int +do_command(char *buf) +{ + size_t len; + char *args, *cmd; + + len = strlen(buf); + args = (char *)get_token(buf, 1, ",", IGNORE_WHITE, cmd = buf); + if (args) { + if (strcmp("creat", cmd) == 0) + return do_creat(args); + if (strcmp("mnt", cmd) == 0) + return do_mnt(args); + if (strcmp("cd", cmd) == 0) + return do_cd(args); + if (strcmp("chmd", cmd) == 0) + return do_chmd(args); + } + return -EINVAL; +} + +/* + * Given a command sequence buffer, parse it and run the given + * commands + */ +int +_sysio_boot(const char *buf) +{ + char c, *tok; + int err; + + /* + * Allocate token buffer. + */ + tok = malloc(strlen(buf)); + if (!tok) + return -ENOMEM; + err = 0; + while (1) { + /* + * Discard leading white space. + */ + while ((c = *buf) != '\0' && + !(c == '{' || strchr(IGNORE_WHITE, c) == NULL)) + buf++; + if (c == '\0') + break; + if (c != '{') { + err = -EINVAL; + break; + } + /* + * Get the command. + */ + buf = (char *)get_token(buf + 1, 0, "}", IGNORE_WHITE, tok); + if (!buf) { + err = -EINVAL; + break; + } + /* + * Perform. + */ + err = do_command(tok); + if (err) + break; + } + free(tok); + return err; +} diff --git a/libsysio/src/inode.c b/libsysio/src/inode.c new file mode 100644 index 0000000..6615918 --- /dev/null +++ b/libsysio/src/inode.c @@ -0,0 +1,958 @@ +/* + * This Cplant(TM) source code is the property of Sandia National + * Laboratories. + * + * This Cplant(TM) source code is copyrighted by Sandia National + * Laboratories. + * + * The redistribution of this Cplant(TM) source code is subject to the + * terms of the GNU Lesser General Public License + * (see cit/LGPL or http://www.gnu.org/licenses/lgpl.html) + * + * Cplant(TM) Copyright 1998-2003 Sandia Corporation. + * Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive + * license for use of this work by or on behalf of the US Government. + * Export of this program may require a license from the United States + * Government. + */ + +/* + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Questions or comments about this library should be sent to: + * + * Lee Ward + * Sandia National Laboratories, New Mexico + * P.O. Box 5800 + * Albuquerque, NM 87185-1110 + * + * lee@sandia.gov + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "sysio.h" +#include "fs.h" +#include "mount.h" +#include "inode.h" +#include "dev.h" + +/* + * Support for path and index nodes. + */ + +/* + * Size of all names bucket-hash table. + */ +#ifndef NAMES_TABLE_LEN +#define NAMES_TABLE_LEN 251 +#endif + +/* + * Desired i-nodes cache size is MAX_INODES_MULTIPLIER times the number + * of slots in the names hash table. + */ +#define MAX_INODES_MULTIPLIER 3 + +/* + * Active i-nodes in the system and the number of same. + */ +struct inodes_head _sysio_inodes; +static size_t n_inodes = 0; +/* + * Desired number of active i-nodes. + */ +static size_t max_inodes = (MAX_INODES_MULTIPLIER * NAMES_TABLE_LEN); + +/* + * System table for rapid access to component names. + */ +static LIST_HEAD(, pnode_base) names[NAMES_TABLE_LEN]; +/* + * Number of names tracked by the system. + */ +static size_t n_names = 0; +/* + * Desired number of base path nodes to maintain. + */ +static size_t max_names = (2 * NAMES_TABLE_LEN); + +/* + * Number of pnodes to grab per memory allocation when filling the + * free list. + */ +#define PNODES_PER_CHUNK ((8 * 1024) / sizeof(struct pnode) - 2) + +#if ZERO_SUM_MEMORY +/* + * Allocation information for pnodes bulk allocation. + */ +struct pnodes_block { + LIST_ENTRY(pnodes_block) pnblk_links; + struct pnode pnblk_nodes[PNODES_PER_CHUNK]; +}; + +static LIST_HEAD( ,pnodes_block) pnblocks; +#endif + +/* + * List of all path-nodes (aliases) referenced by any tree. + */ +struct pnodes_head _sysio_pnodes; + +/* + * Free path-nodes -- Not referenced by any tree for fas reuse. + */ +static LIST_HEAD( ,pnode) free_pnodes; + +/* + * The system root -- Aka `/'. + */ +struct pnode *_sysio_root = NULL; + +/* + * Initialize path and i-node support. Must be called before any other + * routine in this module. + */ +int +_sysio_i_init() +{ + unsigned i; + + TAILQ_INIT(&_sysio_inodes); + + for (i = 0; i < NAMES_TABLE_LEN; i++) + LIST_INIT(&names[i]); + +#if ZERO_SUM_MEMORY + LIST_INIT(&pnblocks); +#endif + TAILQ_INIT(&_sysio_pnodes); + LIST_INIT(&free_pnodes); + + return 0; +} + +/* + * Garbage-collect idle i-nodes. We try to keep resource use limited to + * MAX_INODES_MULTIPLIER * max_names. + */ +static void +i_reclaim() +{ + struct inode *next, *ino; + size_t t; + + /* + * I just can't figure out a good way to reclaim these well without + * getting really fancy and using complex algorithms. The + * base nodes hold references on them for a long time and then + * release them. Those will age to the front of the queue and + * we have to skip over them. Oh well... + */ + t = MAX_INODES_MULTIPLIER * max_names; + if (max_inodes < t) { + /* + * Oops. Nope. We want more inodes than names entries. + */ + max_inodes = t; + return; + } + next = _sysio_inodes.tqh_first; + if (!next) + return; + t = max_inodes / 2; + do { + ino = next; + next = ino->i_nodes.tqe_next; + if (ino->i_ref || ino->i_immune) + continue; + _sysio_i_gone(ino); + } while (next && n_inodes > t); + + if (n_inodes > t) + max_inodes += t; +} + +static unsigned +hash(struct file_identifier *fid) +{ + size_t n; + unsigned char *ucp; + unsigned hkey; + + n = fid->fid_len; + ucp = fid->fid_data; + hkey = 0; + do { + hkey <<= 1; + hkey += *ucp++; + } while (--n); + return hkey; +} + +/* + * Allocate and initialize a new i-node. Returned i-node is referenced. + * + * NB: The passed file identifier is not copied. It is, therefor, up to the + * caller to assure that the value is static until the inode is destroyed. + */ +struct inode * +_sysio_i_new(struct filesys *fs, + struct file_identifier *fid, + mode_t type, + dev_t rdev, + unsigned immunity, + struct inode_ops *ops, + void *private) +{ + struct inode *ino; + struct itable_entry *head; + struct inode_ops operations; + + if (n_inodes > max_inodes) { + /* + * Try to limit growth. + */ + i_reclaim(); + } + + ino = malloc(sizeof(struct inode)); + if (!ino) + return NULL; + ino->i_ops = *ops; + operations = *ops; + if (S_ISBLK(type) || S_ISCHR(type) || S_ISFIFO(type)) { + struct inode_ops *o; + + /* + * Replace some operations sent with + * those from the device table. + */ + o = _sysio_dev_lookup(type, rdev); + operations.inop_open = o->inop_open; + operations.inop_close = o->inop_close; + operations.inop_read = o->inop_read; + operations.inop_write = o->inop_write; + operations.inop_pos = o->inop_pos; + operations.inop_iodone = o->inop_iodone; + operations.inop_datasync = o->inop_datasync; + operations.inop_ioctl = o->inop_ioctl; + } + I_INIT(ino, fs, type, rdev, &operations, fid, immunity, private); + ino->i_ref = 1; + TAILQ_INSERT_TAIL(&_sysio_inodes, ino, i_nodes); + head = &fs->fs_itbl[hash(fid) % FS_ITBLSIZ]; + LIST_INSERT_HEAD(head, ino, i_link); + + n_inodes++; + assert(n_inodes); + + return ino; +} + +/* + * Find existing i-node given i-number and pointers to FS record + * and identifier. + */ +struct inode * +_sysio_i_find(struct filesys *fs, struct file_identifier *fid) +{ + struct inode *ino; + struct itable_entry *head; + + head = &fs->fs_itbl[hash(fid) % FS_ITBLSIZ]; + /* + * Look for existing. + */ + for (ino = head->lh_first; ino; ino = ino->i_link.le_next) + if (ino->i_fid->fid_len == fid->fid_len && + memcmp(ino->i_fid->fid_data, + fid->fid_data, + fid->fid_len) == 0) { + I_REF(ino); + break; + } + + return ino; +} + +/* + * Force reclaim of idle i-node. + */ +void +_sysio_i_gone(struct inode *ino) +{ + + if (ino->i_ref) + abort(); + if (!ino->i_zombie) + LIST_REMOVE(ino, i_link); + TAILQ_REMOVE(&_sysio_inodes, ino, i_nodes); + (*ino->i_ops.inop_gone)(ino); + free(ino); + + assert(n_inodes); + n_inodes--; +} + +/* + * Stale inode, zombie it and move it out of the way + */ +void +_sysio_i_undead(struct inode *ino) +{ + + LIST_REMOVE(ino, i_link); + ino->i_zombie = 1; +} + +/* + * Garbage collect idle path (and base path) nodes tracked by the system. + */ +static void +p_reclaim() +{ + struct pnode *next, *pno; + size_t t; + + next = _sysio_pnodes.tqh_first; + if (!next) + return; + t = max_names / 2; + do { + pno = next; + if (pno->p_ref) { + next = pno->p_nodes.tqe_next; + continue; + } + pno->p_ref++; + assert(pno->p_ref); + (void )_sysio_p_prune(pno); + next = pno->p_nodes.tqe_next; + assert(pno->p_ref); + pno->p_ref--; + if (pno->p_ref) + continue; + (void )_sysio_p_prune(pno); + } while (n_names > t && next); + + if (n_names > t) + max_names += t; +} + +/* + * Allocate and initialize a new base path node. + */ +struct pnode_base * +_sysio_pb_new(struct qstr *name, struct pnode_base *parent, struct inode *ino) +{ + struct pnode_base *pb; + + if (n_names > max_names) { + /* + * Try to limit growth. + */ + p_reclaim(); + } + + pb = malloc(sizeof(struct pnode_base) + name->len); + if (!pb) + return NULL; + + pb->pb_name.name = NULL; + pb->pb_name.len = name->len; + if (pb->pb_name.len) { + char *cp; + + /* + * Copy the passed name. + * + * We have put the space for the name immediately behind + * the record in order to maximize spatial locality. + */ + cp = (char *)pb + sizeof(struct pnode_base); + (void )strncpy(cp, name->name, name->len); + pb->pb_name.name = cp; + assert(name->hashval); + pb->pb_name.hashval = name->hashval; + LIST_INSERT_HEAD(&names[name->hashval % NAMES_TABLE_LEN], + pb, + pb_names); + } + pb->pb_ino = ino; + LIST_INIT(&pb->pb_children); + LIST_INIT(&pb->pb_aliases); + if (parent) + LIST_INSERT_HEAD(&parent->pb_children, pb, pb_sibs); + pb->pb_parent = parent; + + n_names++; + assert(n_names); + + return pb; +} + +/* + * Destroy base path node, releasing resources back to the system. + * + * NB: Caller must release the inode referenced by the record. + */ +static void +pb_destroy(struct pnode_base *pb) +{ + + assert(n_names); + n_names--; + + assert(!pb->pb_aliases.lh_first); + assert(!pb->pb_children.lh_first); + assert(!pb->pb_ino); + if (pb->pb_name.len) + LIST_REMOVE(pb, pb_names); + if (pb->pb_parent) + LIST_REMOVE(pb, pb_sibs); + +#ifndef NDEBUG + /* + * This can help us catch pb-nodes that are free'd redundantly. + */ + pb->pb_name.hashval = 0; +#endif + free(pb); +} + +/* + * Force reclaim of idle base path node. + */ +void +_sysio_pb_gone(struct pnode_base *pb) +{ + + if (pb->pb_ino) + I_RELE(pb->pb_ino); + pb->pb_ino = NULL; + + pb_destroy(pb); +} + +/* + * Generate more path (alias) nodes for the fast allocator. + */ +static void +more_pnodes() +{ + size_t n; +#if ZERO_SUM_MEMORY + struct pnodes_block *pnblk; +#endif + struct pnode *pno; + +#if ZERO_SUM_MEMORY + pnblk = malloc(sizeof(struct pnodes_block)); + pno = NULL; + if (pnblk) { + LIST_INSERT_HEAD(&pnblocks, pnblk, pnblk_links); + pno = pnblk->pnblk_nodes; + } +#else + pno = malloc(PNODES_PER_CHUNK * sizeof(struct pnode)); +#endif + if (!pno) + return; + n = PNODES_PER_CHUNK; + do { + LIST_INSERT_HEAD(&free_pnodes, pno, p_links); + pno++; + } while (--n); +} + +#if ZERO_SUM_MEMORY +/* + * Shutdown + */ +void +_sysio_i_shutdown() +{ + struct pnodes_block *pnblk; + + while ((pnblk = pnblocks.lh_first)) { + LIST_REMOVE(pnblk, pnblk_links); + free(pnblk); + } +} +#endif + +/* + * Allocate, initialize and establish appropriate links for new path (alias) + * node. + */ +struct pnode * +_sysio_p_new_alias(struct pnode *parent, + struct pnode_base *pb, + struct mount *mnt) +{ + struct pnode *pno; + + assert(!pb->pb_name.name || pb->pb_name.hashval); + + pno = free_pnodes.lh_first; + if (!pno) { + more_pnodes(); + pno = free_pnodes.lh_first; + } + if (!pno) + return NULL; + LIST_REMOVE(pno, p_links); + + pno->p_ref = 1; + pno->p_parent = parent; + if (!pno->p_parent) + pno->p_parent = pno; + pno->p_base = pb; + pno->p_mount = mnt; + pno->p_cover = NULL; + LIST_INSERT_HEAD(&pb->pb_aliases, pno, p_links); + TAILQ_INSERT_TAIL(&_sysio_pnodes, pno, p_nodes); + + return pno; +} + +/* + * For reclamation of idle path (alias) node. + */ +void +_sysio_p_gone(struct pnode *pno) +{ + struct pnode_base *pb; + + assert(!pno->p_ref); + assert(!pno->p_cover); + + TAILQ_REMOVE(&_sysio_pnodes, pno, p_nodes); + LIST_REMOVE(pno, p_links); + + pb = pno->p_base; + if (!(pb->pb_aliases.lh_first || pb->pb_children.lh_first)) + _sysio_pb_gone(pb); + + LIST_INSERT_HEAD(&free_pnodes, pno, p_links); +} + +/* + * (Re)Validate passed path node. + */ +int +_sysio_p_validate(struct pnode *pno, struct intent *intnt, const char *path) +{ + struct inode *ino; + struct pnode_base *rootpb; + int err; + + ino = pno->p_base->pb_ino; + /* + * An invalid pnode will not have an associated inode. We'll use + * the FS root inode, then -- It *must* be valid. + */ + rootpb = pno->p_mount->mnt_root->p_base; + assert(rootpb->pb_ino); + err = + rootpb->pb_ino->i_ops.inop_lookup(pno, + &ino, + intnt, + path); + /* + * If the inode lookup returns a different inode, release the old if + * present and point to the new. + */ + if (err || pno->p_base->pb_ino != ino) { + if (pno->p_base->pb_ino) + I_RELE(pno->p_base->pb_ino); + pno->p_base->pb_ino = ino; + } + return err; +} + +/* + * Find (or create!) an alias for the given parent and name. A misnomer, + * really -- This is a "get". Returned path node is referenced. + */ +int +_sysio_p_find_alias(struct pnode *parent, + struct qstr *name, + struct pnode **pnop) +{ + struct pnode_base *pb; + int err; + struct pnode *pno; + + /* + * Find the named child. + */ + if (name->len) { + /* + * Try the names table. + */ + pb = names[name->hashval % NAMES_TABLE_LEN].lh_first; + while (pb) { + if (pb->pb_parent == parent->p_base && + pb->pb_name.len == name->len && + strncmp(pb->pb_name.name, + name->name, + name->len) == 0) + break; + pb = pb->pb_names.le_next; + } + } else { + /* + * Brute force through the parent's list of children. + */ + pb = parent->p_base->pb_children.lh_first; + while (pb) { + if (pb->pb_parent == parent->p_base && + pb->pb_name.len == name->len && + strncmp(pb->pb_name.name, + name->name, + name->len) == 0) + break; + pb = pb->pb_sibs.le_next; + } + } + if (!pb) { + /* + * None found, create new child. + */ + pb = _sysio_pb_new(name, parent->p_base, NULL); + if (!pb) + return -ENOMEM; + } + /* + * Now find the proper alias. It's the one with the passed + * parent. + */ + err = 0; + pno = pb->pb_aliases.lh_first; + while (pno) { + if (pno->p_parent == parent) { + P_REF(pno); + break; + } + pno = pno->p_links.le_next; + } + if (!pno) { + /* + * Hmm. No alias. Just create an invalid one, to be + * validated later. + */ + pno = _sysio_p_new_alias(parent, pb, parent->p_mount); + if (!pno) + err = -ENOMEM; + } + if (!err) + *pnop = pno; + return err; +} + +/* + * Prune idle path base nodes freom the passed sub-tree, including the root. + */ +static void +_sysio_prune(struct pnode_base *rpb) +{ + struct pnode_base *nxtpb, *pb; + + nxtpb = rpb->pb_children.lh_first; + while ((pb = nxtpb)) { + nxtpb = pb->pb_sibs.le_next; + if (pb->pb_aliases.lh_first) + continue; + if (pb->pb_children.lh_first) { + _sysio_prune(pb); + continue; + } + _sysio_pb_gone(pb); + } + if (rpb->pb_children.lh_first) + return; + _sysio_pb_gone(rpb); +} + +/* + * Prune idle nodes from the passed sub-tree, including the root. + * + * Returns the number of aliases on the same mount that could not be pruned. + * i.e. a zero return means the entire sub-tree is gone. + */ +size_t +_sysio_p_prune(struct pnode *root) +{ + size_t count; + struct pnode_base *nxtpb, *pb; + struct pnode *nxtpno, *pno; + + count = 0; + nxtpb = root->p_base->pb_children.lh_first; + while ((pb = nxtpb)) { + nxtpb = pb->pb_sibs.le_next; + nxtpno = pb->pb_aliases.lh_first; + if (!nxtpno) { + _sysio_prune(pb); + continue; + } + while ((pno = nxtpno)) { + nxtpno = pno->p_links.le_next; + if (pno->p_mount != root->p_mount) { + /* + * Not the alias we were looking for. + */ + continue; + } + if (pno->p_base->pb_children.lh_first) { + /* + * Node is interior. Recurse. + */ + count += _sysio_p_prune(pno); + continue; + } + if (pno->p_ref) { + /* + * Can't prune; It's active. + */ + count++; + continue; + } + assert(!pno->p_cover); /* covered => ref'd! */ + assert(!pno->p_base->pb_name.name || + pno->p_base->pb_name.hashval); + /* + * Ok to prune. + */ + if (pno->p_mount->mnt_root == pno) { +#ifndef AUTOMOUNT_FILE_NAME + count++; + continue; +#else + /* + * This is an automount-point. Must + * unmount before relcaim. + */ + P_REF(pno); + if (_sysio_do_unmount(pno->p_mount) != 0) { + P_RELE(pno); + count++; + } + continue; +#endif + } + _sysio_p_gone(pno); + } + } + + if (count) { + /* + * Can't get the root or we disconnect the sub-trees. + */ + return count + (root->p_ref ? 1 : 0); + } + + /* + * All that is left is the root. Try for it too. + */ + if (root->p_ref) { + count++; + } else if (root->p_mount->mnt_root == root) { +#ifndef AUTOMOUNT_FILE_NAME + count++; +#else + /* + * This is an automount-point. Must + * unmount before relcaim. + */ + P_REF(root); + if (_sysio_do_unmount(root->p_mount) != 0) { + P_RELE(root); + count++; + } +#endif + } else + _sysio_p_gone(root); + + return count; +} + +/* + * Return path tracked by the base path node ancestor chain. + * + * Remember, base path nodes track the path relative to the file system and + * path (alias) nodes track path relative to our name space -- They cross + * mount points. + */ +char * +_sysio_pb_path(struct pnode_base *pb, const char separator) +{ + char *buf; + size_t len, n; + struct pnode_base *tmp; + char *cp; + + /* + * First pass: Traverse to the root of the sub-tree, remembering + * lengths. + */ + len = 0; + tmp = pb; + do { + n = tmp->pb_name.len; + len += tmp->pb_name.len; + if (n) + len++; + tmp = tmp->pb_parent; + } while (tmp); + if (!len) + len++; + /* + * Alloc space. + */ + buf = malloc(len + 1); + if (!buf) + return NULL; + /* + * Fill in the path buffer -- Backwards, since we're starting + * from the end. + */ + cp = buf; + *cp = separator; + cp += len; + *cp = '\0'; /* NUL term */ + tmp = pb; + do { + cp -= tmp->pb_name.len; + n = tmp->pb_name.len; + if (n) { + (void )strncpy(cp, tmp->pb_name.name, n); + *--cp = separator; + } + tmp = tmp->pb_parent; + } while (tmp); + + return buf; +} + +/* + * Common set attributes routine. + */ +int +_sysio_setattr(struct pnode *pno, + struct inode *ino, + unsigned mask, + struct intnl_stat *stbuf) +{ + /* It is possible that pno is null (for ftruncate call). */ + + if (pno) { + assert(!(pno->p_base->pb_ino && ino) || pno->p_base->pb_ino == ino); + if (IS_RDONLY(pno, ino)) + return -EROFS; + } + if (!ino && pno->p_base->pb_ino) + ino = pno->p_base->pb_ino; + return (*ino->i_ops.inop_setattr)(pno, ino, mask, stbuf); +} + +/* + * Do nothing. + */ +void +_sysio_do_noop() +{ + + return; +} + +/* + * Abort. + */ +void +_sysio_do_illop() +{ + + abort(); +} + +/* + * Return -EBADF + */ +int +_sysio_do_ebadf() +{ + + return -EBADF; +} + +/* + * Return -EINVAL + */ +int +_sysio_do_einval() +{ + + return -EINVAL; +} + +/* + * Return -ENOENT + */ +int +_sysio_do_enoent() +{ + + return -ENOENT; +} + +/* + * Return -ESPIPE + */ +int +_sysio_do_espipe() +{ + + return -ESPIPE; +} + +/* + * Return -EISDIR + */ +int +_sysio_do_eisdir() +{ + + return -EISDIR; +} + +/* + * Return -ENOSYS + */ +int +_sysio_do_enosys() +{ + + return -ENOSYS; +} diff --git a/libsysio/src/ioctl.c b/libsysio/src/ioctl.c new file mode 100644 index 0000000..d157c9b --- /dev/null +++ b/libsysio/src/ioctl.c @@ -0,0 +1,90 @@ +/* + * This Cplant(TM) source code is the property of Sandia National + * Laboratories. + * + * This Cplant(TM) source code is copyrighted by Sandia National + * Laboratories. + * + * The redistribution of this Cplant(TM) source code is subject to the + * terms of the GNU Lesser General Public License + * (see cit/LGPL or http://www.gnu.org/licenses/lgpl.html) + * + * Cplant(TM) Copyright 1998-2003 Sandia Corporation. + * Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive + * license for use of this work by or on behalf of the US Government. + * Export of this program may require a license from the United States + * Government. + */ + +/* + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Questions or comments about this library should be sent to: + * + * Lee Ward + * Sandia National Laboratories, New Mexico + * P.O. Box 5800 + * Albuquerque, NM 87185-1110 + * + * lee@sandia.gov + */ + +#include +#include +#include +#include + +#include "sysio.h" +#include "inode.h" +#include "file.h" + +#include "sysio-symbols.h" + +int +SYSIO_INTERFACE_NAME(ioctl)(int fd, unsigned long request, ...) +{ + int err; + struct file *fil; + va_list ap; + SYSIO_INTERFACE_DISPLAY_BLOCK; + + SYSIO_INTERFACE_ENTER; + err = 0; + fil = _sysio_fd_find(fd); + if (!fil) { + err = -EBADF; + goto out; + } + + va_start(ap, request); + err = fil->f_ino->i_ops.inop_ioctl(fil->f_ino, request, ap); + va_end(ap); + +out: + SYSIO_INTERFACE_RETURN(err ? -1 : 0, err); +} + + +#ifdef __GLIBC__ +#undef __ioctl +sysio_sym_weak_alias(SYSIO_INTERFACE_NAME(ioctl), + PREPEND(__, SYSIO_INTERFACE_NAME(ioctl))) +#endif + +#ifdef BSD +#undef _ioctl +sysio_sym_weak_alias(SYSIO_INTERFACE_NAME(ioctl), + PREPEND(_, SYSIO_INTERFACE_NAME(ioctl))) +#endif diff --git a/libsysio/src/ioctx.c b/libsysio/src/ioctx.c new file mode 100644 index 0000000..70c1b3e --- /dev/null +++ b/libsysio/src/ioctx.c @@ -0,0 +1,549 @@ +/* + * This Cplant(TM) source code is the property of Sandia National + * Laboratories. + * + * This Cplant(TM) source code is copyrighted by Sandia National + * Laboratories. + * + * The redistribution of this Cplant(TM) source code is subject to the + * terms of the GNU Lesser General Public License + * (see cit/LGPL or http://www.gnu.org/licenses/lgpl.html) + * + * Cplant(TM) Copyright 1998-2004 Sandia Corporation. + * Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive + * license for use of this work by or on behalf of the US Government. + * Export of this program may require a license from the United States + * Government. + */ + +/* + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Questions or comments about this library should be sent to: + * + * Lee Ward + * Sandia National Laboratories, New Mexico + * P.O. Box 5800 + * Albuquerque, NM 87185-1110 + * + * lee@sandia.gov + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "sysio.h" +#include "inode.h" +#include "xtio.h" + +/* + * Asynchronous IO context support. + */ + +/* + * Arguments to IO vector enumerator callback when used by _sysio_doio(). + */ +struct doio_helper_args { + ssize_t (*f)(void *, size_t, _SYSIO_OFF_T, void *); /* base func */ + void *arg; /* caller arg */ +}; + +/* + * List of all outstanding (in-flight) asynch IO requests tracked + * by the system. + */ +static LIST_HEAD( ,ioctx) aioq; + +/* + * Free callback entry. + */ +#define cb_free(cb) free(cb) + +/* + * Initialization. Must be called before using any other routine in this + * module. + */ +int +_sysio_ioctx_init() +{ + + LIST_INIT(&aioq); + return 0; +} + +/* + * Enter an IO context onto the async IO events queue. + */ +void +_sysio_ioctx_enter(struct ioctx *ioctx) +{ + + LIST_INSERT_HEAD(&aioq, ioctx, ioctx_link); +} + +/* + * Allocate and initialize a new IO context. + */ +struct ioctx * +_sysio_ioctx_new(struct inode *ino, + int wr, + const struct iovec *iov, + size_t iovlen, + const struct intnl_xtvec *xtv, + size_t xtvlen) +{ + struct ioctx *ioctx; + + ioctx = malloc(sizeof(struct ioctx)); + if (!ioctx) + return NULL; + + I_REF(ino); + + IOCTX_INIT(ioctx, + 0, + (ioid_t )ioctx, + wr, + ino, + iov, iovlen, + xtv, xtvlen); + + /* + * Link request onto the outstanding requests queue. + */ + _sysio_ioctx_enter(ioctx); + + return ioctx; +} + +/* + * Add an IO completion call-back to the end of the context call-back queue. + * These are called in iowait() as the last thing, right before the context + * is destroyed. + * + * They are called in order. Beware. + */ +int +_sysio_ioctx_cb(struct ioctx *ioctx, + void (*f)(struct ioctx *, void *), + void *data) +{ + struct ioctx_callback *entry; + + entry = malloc(sizeof(struct ioctx_callback)); + if (!entry) + return -ENOMEM; + + entry->iocb_f = f; + entry->iocb_data = data; + + TAILQ_INSERT_TAIL(&ioctx->ioctx_cbq, entry, iocb_next); + + return 0; +} + +/* + * Find an IO context given it's identifier. + * + * NB: This is dog-slow. If there are alot of these, we will need to change + * this implementation. + */ +struct ioctx * +_sysio_ioctx_find(ioid_t id) +{ + struct ioctx *ioctx; + + for (ioctx = aioq.lh_first; ioctx; ioctx = ioctx->ioctx_link.le_next) + if (ioctx->ioctx_id == id) + return ioctx; + + return NULL; +} + +/* + * Wait for asynchronous IO operation to complete, return status + * and dispose of the context. + * + * Note: + * The context is no longer valid after return. + */ +ssize_t +_sysio_ioctx_wait(struct ioctx *ioctx) +{ + ssize_t cc; + + /* + * Wait for async operation to complete. + */ + while (!(ioctx->ioctx_done || + (*ioctx->ioctx_ino->i_ops.inop_iodone)(ioctx))) + ; + + /* + * Get status. + */ + cc = ioctx->ioctx_cc; + if (cc < 0) + cc = -ioctx->ioctx_errno; + + /* + * Dispose. + */ + _sysio_ioctx_complete(ioctx); + + return cc; +} + +/* + * Free callback entry. + */ +void +_sysio_ioctx_cb_free(struct ioctx_callback *cb) +{ + + cb_free(cb); +} + +/* + * Complete an asynchronous IO request. + */ +void +_sysio_ioctx_complete(struct ioctx *ioctx) +{ + struct ioctx_callback *entry; + + /* + * Run the call-back queue. + */ + while ((entry = ioctx->ioctx_cbq.tqh_first)) { + TAILQ_REMOVE(&ioctx->ioctx_cbq, entry, iocb_next); + (*entry->iocb_f)(ioctx, entry->iocb_data); + cb_free(entry); + } + + /* + * Unlink from the file record's outstanding request queue. + */ + LIST_REMOVE(ioctx, ioctx_link); + + if (ioctx->ioctx_fast) + return; + + I_RELE(ioctx->ioctx_ino); + + free(ioctx); +} + +/* + * General help validating strided-IO vectors. + * + * A driver may call this to make sure underflow/overflow of an off_t can't + * occur and overflow of a ssize_t can't occur when writing. The sum + * of the reconciled transfer length is returned or some appropriate + * error depending on underflow/overflow. + * + * The following algorithm assumes: + * + * a) sizeof(size_t) >= sizeof(ssize_t) + * b) 2's complement arithmetic + * c) The compiler won't optimize away code because it's developers + * believed that something with an undefined result in `C' can't happen. + */ +ssize_t +_sysio_validx(const struct intnl_xtvec *xtv, size_t xtvlen, + const struct iovec *iov, size_t iovlen, + _SYSIO_OFF_T limit) +{ + ssize_t acc, cc; + struct iovec iovec; + struct intnl_xtvec xtvec; + _SYSIO_OFF_T off; + + if (!(xtvlen && iovlen)) + return -EINVAL; + + acc = 0; + xtvec.xtv_len = iovec.iov_len = 0; + do { + while (!xtvec.xtv_len) { + if (!xtvlen--) + break; + if (!xtv->xtv_len) { + xtv++; + continue; + } + xtvec = *xtv++; + if (xtvec.xtv_off < 0) + return -EINVAL; + } + if (!xtvec.xtv_len) + break; + do { + while (!iovec.iov_len) { + if (!iovlen--) + break; + if (!iov->iov_len) { + iov++; + continue; + } + iovec = *iov++; + } + if (!iovec.iov_len) + break; + cc = iovec.iov_len; + if (cc < 0) + return -EINVAL; + if ((size_t )cc > xtvec.xtv_len) + cc = xtvec.xtv_len; + xtvec.xtv_len -= cc; + iovec.iov_len -= cc; + off = xtvec.xtv_off + cc; + if (xtvec.xtv_off && off <= xtvec.xtv_off) + return off < 0 ? -EINVAL : -EOVERFLOW; + if (off > limit) + return -EFBIG; + xtvec.xtv_off = off; + cc += acc; + if (acc && (cc <= acc)) + return -EINVAL; + acc = cc; + } while (xtvec.xtv_len && iovlen); + } while ((xtvlen || xtvec.xtv_len) && iovlen); + return acc; +} + +/* + */ +ssize_t +_sysio_enumerate_extents(const struct intnl_xtvec *xtv, size_t xtvlen, + const struct iovec *iov, size_t iovlen, + ssize_t (*f)(const struct iovec *, int, + _SYSIO_OFF_T, + ssize_t, + void *), + void *arg) +{ + ssize_t acc, tmp, cc; + struct iovec iovec; + struct intnl_xtvec xtvec; + const struct iovec *start; + _SYSIO_OFF_T off; + size_t n; + size_t remain; + + acc = 0; + iovec.iov_len = 0; + while (xtvlen) { + /* + * Coalesce contiguous extent vector entries. + */ + off = xtvec.xtv_off = xtv->xtv_off; + off += xtvec.xtv_len = xtv->xtv_len; + while (++xtv, --xtvlen) { + if (off != xtv->xtv_off) { + /* + * Not contiguous. + */ + break; + } + if (!xtv->xtv_len) { + /* + * Zero length. + */ + continue; + } + off += xtv->xtv_len; + xtvec.xtv_len += xtv->xtv_len; + } + while (xtvec.xtv_len) { + if (iovec.iov_len) { + tmp = iovec.iov_len; + if (iovec.iov_len > xtvec.xtv_len) { + iovec.iov_len = xtvec.xtv_len; + } + cc = + (*f)(&iovec, 1, + xtvec.xtv_off, + xtvec.xtv_len, + arg); + if (cc <= 0) { + if (acc) + return acc; + return cc; + } + iovec.iov_base = (char *)iovec.iov_base + cc; + iovec.iov_len = tmp - cc; + tmp = cc + acc; + if (acc && tmp <= acc) + abort(); /* paranoia */ + acc = tmp; + } else { + start = iov; + n = xtvec.xtv_len; + do { + if (iov->iov_len > n) { + /* + * That'll do. + */ + break; + } + n -= iov->iov_len; + iov++; + } while (--iovlen); + if (iov == start) { + iovec = *iov++; +#if 0 + if (iovec.iov_len > n) { + iovec.iov_len = n; + } +#endif + continue; + } + remain = xtvec.xtv_len - n; + cc = + (*f)(start, iov - start, + xtvec.xtv_off, + xtvec.xtv_len - n, + arg); + if (cc <= 0) { + if (acc) + return acc; + return cc; + } + + tmp = cc + acc; + if (acc && tmp <= acc) + abort(); /* paranoia */ + acc = tmp; + + if (remain && !iovlen) + return acc; + + remain -= cc; + if (remain) + return acc; /* short */ + } + xtvec.xtv_off += cc; + xtvec.xtv_len -= cc; + } + } + return acc; +} + +ssize_t +_sysio_enumerate_iovec(const struct iovec *iov, size_t count, + _SYSIO_OFF_T off, + ssize_t limit, + ssize_t (*f)(void *, size_t, _SYSIO_OFF_T, void *), + void *arg) +{ + ssize_t acc, cc; + size_t n; + unsigned indx; + size_t remain; + + if (!count) + return -EINVAL; + assert(limit >= 0); + acc = 0; + n = limit; + for (indx = 0; n && indx < count; indx++) { + if (iov[indx].iov_len < n) { + cc = (ssize_t )iov[indx].iov_len; + if (cc < 0) + return -EINVAL; + } else + cc = (ssize_t )n; + if (!cc) + continue; + n -= cc; + cc += acc; + if (acc && cc <= acc) + return -EINVAL; + acc = cc; + } + if (!acc) + return 0; + acc = 0; + do { + if (!iov->iov_len) { + iov++; + continue; + } + n = + iov->iov_len < (size_t )limit + ? iov->iov_len + : (size_t )limit; + cc = (*f)(iov->iov_base, n, off, arg); + if (cc <= 0) { + if (acc) + return acc; + return cc; + } + off += cc; + limit -= cc; + remain = iov->iov_len - cc; + cc += acc; + if (acc && cc <= acc) + abort(); /* bad driver! */ + acc = cc; + if (remain || !limit) + break; /* short/limited read */ + iov++; + } while (--count); + return acc; +} + +static ssize_t +_sysio_doio_helper(const struct iovec *iov, int count, + _SYSIO_OFF_T off, + ssize_t limit, + struct doio_helper_args *args) +{ + + return _sysio_enumerate_iovec(iov, count, + off, limit, + args->f, + args->arg); +} + +/* + * A meta-driver for the whole strided-io process. Appropriate when + * the driver can't handle anything but simple p{read,write}-like + * interface. + */ +ssize_t +_sysio_doio(const struct intnl_xtvec *xtv, size_t xtvlen, + const struct iovec *iov, size_t iovlen, + ssize_t (*f)(void *, size_t, _SYSIO_OFF_T, void *), + void *arg) +{ + struct doio_helper_args arguments; + + arguments.f = f; + arguments.arg = arg; + return _sysio_enumerate_extents(xtv, xtvlen, + iov, iovlen, + (ssize_t (*)(const struct iovec *, int, + _SYSIO_OFF_T, + ssize_t, + void *))_sysio_doio_helper, + &arguments); +} diff --git a/libsysio/src/iowait.c b/libsysio/src/iowait.c new file mode 100644 index 0000000..28035e3 --- /dev/null +++ b/libsysio/src/iowait.c @@ -0,0 +1,97 @@ +/* + * This Cplant(TM) source code is the property of Sandia National + * Laboratories. + * + * This Cplant(TM) source code is copyrighted by Sandia National + * Laboratories. + * + * The redistribution of this Cplant(TM) source code is subject to the + * terms of the GNU Lesser General Public License + * (see cit/LGPL or http://www.gnu.org/licenses/lgpl.html) + * + * Cplant(TM) Copyright 1998-2003 Sandia Corporation. + * Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive + * license for use of this work by or on behalf of the US Government. + * Export of this program may require a license from the United States + * Government. + */ + +/* + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Questions or comments about this library should be sent to: + * + * Lee Ward + * Sandia National Laboratories, New Mexico + * P.O. Box 5800 + * Albuquerque, NM 87185-1110 + * + * lee@sandia.gov + */ + +#include +#include +#include + +#include "sysio.h" +#include "inode.h" + +/* + * Asynch IO support for the API. + */ + +/* + * Poll status of asynch IO request. + */ +int +SYSIO_INTERFACE_NAME(iodone)(ioid_t ioid) +{ + struct ioctx *ioctx; + int rc; + SYSIO_INTERFACE_DISPLAY_BLOCK; + + SYSIO_INTERFACE_ENTER; + ioctx = _sysio_ioctx_find(ioid); + if (!ioctx) + SYSIO_INTERFACE_RETURN(-1, -EINVAL); + + rc = + (ioctx->ioctx_done || + (*ioctx->ioctx_ino->i_ops.inop_iodone)(ioctx)); + + SYSIO_INTERFACE_RETURN(rc < 0 ? -1 : rc, rc < 0 ? rc : 0); +} + +/* + * Wait for completion of and return results from identified asynch IO + * request. + * + * The identifier is no longer valid after return. + */ +ssize_t +SYSIO_INTERFACE_NAME(iowait)(ioid_t ioid) +{ + struct ioctx *ioctx; + ssize_t cc; + SYSIO_INTERFACE_DISPLAY_BLOCK; + + SYSIO_INTERFACE_ENTER; + ioctx = _sysio_ioctx_find(ioid); + if (!ioctx) + SYSIO_INTERFACE_RETURN(-1, -EINVAL); + + cc = _sysio_ioctx_wait(ioctx); + SYSIO_INTERFACE_RETURN(cc < 0 ? -1 : cc, cc < 0 ? (int )cc : 0); +} diff --git a/libsysio/src/link.c b/libsysio/src/link.c new file mode 100644 index 0000000..4c278b5 --- /dev/null +++ b/libsysio/src/link.c @@ -0,0 +1,109 @@ +/* + * This Cplant(TM) source code is the property of Sandia National + * Laboratories. + * + * This Cplant(TM) source code is copyrighted by Sandia National + * Laboratories. + * + * The redistribution of this Cplant(TM) source code is subject to the + * terms of the GNU Lesser General Public License + * (see cit/LGPL or http://www.gnu.org/licenses/lgpl.html) + * + * Cplant(TM) Copyright 1998-2003 Sandia Corporation. + * Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive + * license for use of this work by or on behalf of the US Government. + * Export of this program may require a license from the United States + * Government. + */ + +/* + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Questions or comments about this library should be sent to: + * + * Lee Ward + * Sandia National Laboratories, New Mexico + * P.O. Box 5800 + * Albuquerque, NM 87185-1110 + * + * lee@sandia.gov + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "sysio.h" +#include "mount.h" +#include "inode.h" +#include "sysio-symbols.h" + +int +SYSIO_INTERFACE_NAME(link)(const char *oldpath, const char *newpath) +{ + struct intent intent; + int err; + struct pnode *old, *new; + SYSIO_INTERFACE_DISPLAY_BLOCK; + + SYSIO_INTERFACE_ENTER; + INTENT_INIT(&intent, 0, NULL, NULL); + err = _sysio_namei(_sysio_cwd, oldpath, 0, &intent, &old); + if (err) + goto out; + if (S_ISDIR(old->p_base->pb_ino->i_mode)) { + err = -EPERM; + goto error1; + } + INTENT_INIT(&intent, INT_UPDPARENT, NULL, NULL); + new = NULL; + err = _sysio_namei(_sysio_cwd, newpath, ND_NEGOK, &intent, &new); + if (err) + goto error1; + if (new->p_base->pb_ino) { + err = -EEXIST; + goto error2; + } + if (old->p_mount->mnt_root != new->p_mount->mnt_root) { + err = -EXDEV; + goto error2; + } + err = old->p_base->pb_ino->i_ops.inop_link(old, new); + if (err) + goto error2; + /* + * The new p-node must be pointed at the inode referenced by the old. + */ + assert(!new->p_base->pb_ino && old->p_base->pb_ino); + new->p_base->pb_ino = old->p_base->pb_ino; + I_REF(new->p_base->pb_ino); + +error2: + P_RELE(new); +error1: + P_RELE(old); +out: + SYSIO_INTERFACE_RETURN(err ? -1 : 0, err); +} + +#ifdef REDSTORM +#undef __link +sysio_sym_weak_alias(SYSIO_INTERFACE_NAME(link), + PREPEND(__, SYSIO_INTERFACE_NAME(link))) +#endif diff --git a/libsysio/src/lseek.c b/libsysio/src/lseek.c new file mode 100644 index 0000000..d16efc4 --- /dev/null +++ b/libsysio/src/lseek.c @@ -0,0 +1,175 @@ +/* + * This Cplant(TM) source code is the property of Sandia National + * Laboratories. + * + * This Cplant(TM) source code is copyrighted by Sandia National + * Laboratories. + * + * The redistribution of this Cplant(TM) source code is subject to the + * terms of the GNU Lesser General Public License + * (see cit/LGPL or http://www.gnu.org/licenses/lgpl.html) + * + * Cplant(TM) Copyright 1998-2003 Sandia Corporation. + * Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive + * license for use of this work by or on behalf of the US Government. + * Export of this program may require a license from the United States + * Government. + */ + +/* + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Questions or comments about this library should be sent to: + * + * Lee Ward + * Sandia National Laboratories, New Mexico + * P.O. Box 5800 + * Albuquerque, NM 87185-1110 + * + * lee@sandia.gov + */ + +#include +#include +#include +#include +#include +#include + +#include "sysio.h" +#include "inode.h" +#include "file.h" + +#include "sysio-symbols.h" + +static _SYSIO_OFF_T +_sysio_lseek(int fd, _SYSIO_OFF_T offset, int whence) +{ + struct file *fil; + _SYSIO_OFF_T off, pos; + struct intnl_stat stbuf; + SYSIO_INTERFACE_DISPLAY_BLOCK; + + SYSIO_INTERFACE_ENTER; + fil = _sysio_fd_find(fd); + if (!fil) + return -EBADF; + + off = -1; + switch (whence) { + + case SEEK_SET: + off = 0; + break; + case SEEK_CUR: + off = fil->f_pos; + break; + case SEEK_END: + { + int err; + + err = + (*fil->f_ino->i_ops.inop_getattr)(NULL, + fil->f_ino, + &stbuf); + if (err) + SYSIO_INTERFACE_RETURN((off_t )-1, (int )err); + + } + off = stbuf.st_size; + break; + default: + return -EINVAL; + } + pos = off + offset; + if ((offset < 0 && -offset > off) || (offset > 0 && pos <= off)) + SYSIO_INTERFACE_RETURN((off_t )-1, -EINVAL); + +#ifdef O_LARGEFILE + if (pos >= ((fil->f_flags & O_LARGEFILE) ? _SYSIO_OFF_T_MAX : LONG_MAX)) + SYSIO_INTERFACE_RETURN((off_t )-1, -EOVERFLOW); +#else + if (pos >= _SYSIO_OFF_T_MAX) + SYSIO_INTERFACE_RETURN((off_t )-1, -EOVERFLOW); +#endif + pos = (fil->f_ino->i_ops.inop_pos)(fil->f_ino, pos); + if (pos < 0) + SYSIO_INTERFACE_RETURN((off_t )-1, (int )pos); + fil->f_pos = pos; + SYSIO_INTERFACE_RETURN((off_t )pos, 0); +} + +#if _LARGEFILE64_SOURCE +#undef lseek64 +sysio_sym_weak_alias(_sysio_lseek, SYSIO_INTERFACE_NAME(lseek64)) +#ifdef __GLIBC__ +#undef __lseek64 +sysio_sym_weak_alias(_sysio_lseek, PREPEND(__, SYSIO_INTERFACE_NAME(lseek64))) +#endif +#ifdef REDSTORM +#undef __libc_lseek64 +sysio_sym_weak_alias(_sysio_lseek, + PREPEND(__, SYSIO_INTERFACE_NAME(libc_lseek64))) +#endif +#endif + +#undef lseek + +extern off_t +SYSIO_INTERFACE_NAME(lseek)(int fd, off_t offset, int whence) +{ + _SYSIO_OFF_T off; + off_t rtn; + SYSIO_INTERFACE_DISPLAY_BLOCK; + + SYSIO_INTERFACE_ENTER; + off = _sysio_lseek(fd, offset, whence); + if (off < 0) + SYSIO_INTERFACE_RETURN((off_t )-1, (int )off); + rtn = (off_t )off; + assert(rtn == off); + SYSIO_INTERFACE_RETURN(rtn, 0); +} + +#ifdef __GLIBC__ +#undef __lseek +sysio_sym_weak_alias(SYSIO_INTERFACE_NAME(lseek), + PREPEND(__, SYSIO_INTERFACE_NAME(lseek))) +#endif + +#if 0 +#ifdef __linux__ +#undef llseek +int +SYSIO_INTERFACE_NAME(llseek)(unsigned int fd __IS_UNUSED, + unsigned long offset_high __IS_UNUSED, + unsigned long offset_low __IS_UNUSED, + loff_t *result __IS_UNUSED, + unsigned int whence __IS_UNUSED) +{ + SYSIO_INTERFACE_DISPLAY_BLOCK; + + /* + * Something is very wrong if this was called. + */ + SYSIO_INTERFACE_ENTER; + SYSIO_INTERFACE_RETURN(-1, -ENOTSUP); +} + +#undef __llseek +sysio_sym_weak_alias(SYSIO_INTERFACE_NAME(llseek), + PREPEND(__, SYSIO_INTERFACE_NAME(llseek))) +#endif +#endif diff --git a/libsysio/src/mkdir.c b/libsysio/src/mkdir.c new file mode 100644 index 0000000..c4c6cb5 --- /dev/null +++ b/libsysio/src/mkdir.c @@ -0,0 +1,89 @@ +/* + * This Cplant(TM) source code is the property of Sandia National + * Laboratories. + * + * This Cplant(TM) source code is copyrighted by Sandia National + * Laboratories. + * + * The redistribution of this Cplant(TM) source code is subject to the + * terms of the GNU Lesser General Public License + * (see cit/LGPL or http://www.gnu.org/licenses/lgpl.html) + * + * Cplant(TM) Copyright 1998-2003 Sandia Corporation. + * Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive + * license for use of this work by or on behalf of the US Government. + * Export of this program may require a license from the United States + * Government. + */ + +/* + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Questions or comments about this library should be sent to: + * + * Lee Ward + * Sandia National Laboratories, New Mexico + * P.O. Box 5800 + * Albuquerque, NM 87185-1110 + * + * lee@sandia.gov + */ + +#include +#include +#include +#include +#include + +#include "sysio.h" +#include "inode.h" +#include "fs.h" +#include "mount.h" +#include "sysio-symbols.h" + +int +SYSIO_INTERFACE_NAME(mkdir)(const char *path, mode_t mode) +{ + int err; + struct intent intent; + struct pnode *pno; + SYSIO_INTERFACE_DISPLAY_BLOCK; + + SYSIO_INTERFACE_ENTER; + INTENT_INIT(&intent, INT_CREAT, &mode, NULL); + err = _sysio_namei(_sysio_cwd, path, ND_NEGOK, &intent, &pno); + if (err) + goto out; + if (pno->p_base->pb_ino) { + err = -EEXIST; + goto error; + } + + if (IS_RDONLY(pno, pno->p_base->pb_ino)) { + err = -EROFS; + goto error; + } + err = (*pno->p_parent->p_base->pb_ino->i_ops.inop_mkdir)(pno, mode); +error: + P_RELE(pno); +out: + SYSIO_INTERFACE_RETURN(err ? -1 : 0, err); +} + +#ifdef REDSTORM +#undef __mkdir +sysio_sym_weak_alias(SYSIO_INTERFACE_NAME(mkdir), + PREPEND(__, SYSIO_INTERFACE_NAME(mkdir))) +#endif diff --git a/libsysio/src/mknod.c b/libsysio/src/mknod.c new file mode 100644 index 0000000..4c947d2 --- /dev/null +++ b/libsysio/src/mknod.c @@ -0,0 +1,134 @@ +/* + * This Cplant(TM) source code is the property of Sandia National + * Laboratories. + * + * This Cplant(TM) source code is copyrighted by Sandia National + * Laboratories. + * + * The redistribution of this Cplant(TM) source code is subject to the + * terms of the GNU Lesser General Public License + * (see cit/LGPL or http://www.gnu.org/licenses/lgpl.html) + * + * Cplant(TM) Copyright 1998-2003 Sandia Corporation. + * Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive + * license for use of this work by or on behalf of the US Government. + * Export of this program may require a license from the United States + * Government. + */ + +/* + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Questions or comments about this library should be sent to: + * + * Lee Ward + * Sandia National Laboratories, New Mexico + * P.O. Box 5800 + * Albuquerque, NM 87185-1110 + * + * lee@sandia.gov + */ + +#if defined(__linux__) +#define _BSD_SOURCE +#endif + +#include +#include +#include +#include +#include +#include + +#include "sysio.h" +#include "inode.h" +#include "fs.h" +#include "mount.h" + +#include "sysio-symbols.h" + +#undef mknod +#undef __xmknod + +#if defined(BSD) || defined(REDSTORM) +#define _MKNOD_VER 0 +#endif + +int +PREPEND(__, SYSIO_INTERFACE_NAME(xmknod))(int __ver, + const char *path, + mode_t mode, + dev_t *dev) +{ + int err; + struct intent intent; + struct pnode *pno; + SYSIO_INTERFACE_DISPLAY_BLOCK; + + SYSIO_INTERFACE_ENTER; + if (__ver != _MKNOD_VER) { + err = -ENOSYS; + goto out; + } + + /* + * Support only character-special and fifos right now. + */ + if (!(S_ISCHR(mode) || S_ISFIFO(mode))) { + err = -EINVAL; + goto out; + } + + INTENT_INIT(&intent, INT_CREAT, &mode, NULL); + err = _sysio_namei(_sysio_cwd, path, ND_NEGOK, &intent, &pno); + if (err) + goto out; + if (pno->p_base->pb_ino) { + err = -EEXIST; + goto error; + } + + if (IS_RDONLY(pno, pno->p_base->pb_ino)) { + err = -EROFS; + goto error; + } + err = + (*pno->p_parent->p_base->pb_ino->i_ops.inop_mknod)(pno, mode, *dev); +error: + P_RELE(pno); +out: + SYSIO_INTERFACE_RETURN(err ? -1 : 0, err); +} + +#ifdef REDSTORM +#undef _xmknod +sysio_sym_weak_alias(PREPEND(__, SYSIO_INTERFACE_NAME(xmknod)), + PREPEND(_, SYSIO_INTERFACE_NAME(xmknod))) +#endif + +static int +PREPEND(__, SYSIO_INTERFACE_NAME(mknod))(const char *path, + mode_t mode, + dev_t dev) +{ + + return PREPEND(__, SYSIO_INTERFACE_NAME(xmknod))(_MKNOD_VER, + path, + mode, + &dev); +} + +sysio_sym_weak_alias(PREPEND(__, SYSIO_INTERFACE_NAME(mknod)), + SYSIO_INTERFACE_NAME(mknod)) diff --git a/libsysio/src/module.mk b/libsysio/src/module.mk new file mode 100644 index 0000000..306d18f --- /dev/null +++ b/libsysio/src/module.mk @@ -0,0 +1,31 @@ +# +# Note; Remove statvfs{,64}.c until we decide what to do with them. +# Lee; Tue Feb 24 09:37:32 EST 2004 +# + +if WITH_LUSTRE_HACK +FILE_SUPPORT = src/file_hack.c +else +FILE_SUPPORT = src/file.c +endif + +if WITH_LUSTRE_HACK +LUSTRE_SRCDIR_SRCS = src/stdlib.c +else +LUSTRE_SRCDIR_SRCS = +endif + +SRCDIR_SRCS = src/access.c src/chdir.c src/chmod.c \ + src/chown.c src/dev.c src/dup.c src/fcntl.c \ + src/fs.c src/fsync.c \ + src/getdirentries.c src/init.c src/inode.c \ + src/ioctl.c src/ioctx.c src/iowait.c \ + src/link.c src/lseek.c src/mkdir.c \ + src/mknod.c src/mount.c src/namei.c \ + src/open.c src/rw.c src/rename.c \ + src/rmdir.c src/stat64.c src/stat.c \ + src/symlink.c src/readlink.c \ + src/truncate.c src/unlink.c src/utime.c \ + $(FILE_SUPPORT) $(LUSTRE_SRCDIR_SOURCES) + +SRCDIR_EXTRA = src/module.mk diff --git a/libsysio/src/mount.c b/libsysio/src/mount.c new file mode 100644 index 0000000..3e73832 --- /dev/null +++ b/libsysio/src/mount.c @@ -0,0 +1,680 @@ +/* + * This Cplant(TM) source code is the property of Sandia National + * Laboratories. + * + * This Cplant(TM) source code is copyrighted by Sandia National + * Laboratories. + * + * The redistribution of this Cplant(TM) source code is subject to the + * terms of the GNU Lesser General Public License + * (see cit/LGPL or http://www.gnu.org/licenses/lgpl.html) + * + * Cplant(TM) Copyright 1998-2003 Sandia Corporation. + * Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive + * license for use of this work by or on behalf of the US Government. + * Export of this program may require a license from the United States + * Government. + */ + +/* + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Questions or comments about this library should be sent to: + * + * Lee Ward + * Sandia National Laboratories, New Mexico + * P.O. Box 5800 + * Albuquerque, NM 87185-1110 + * + * lee@sandia.gov + */ + +#include +#include +#include +#include +#include +#include +#ifdef AUTOMOUNT_FILE_NAME +#include +#include +#endif +#include + +#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: + * + * :[[ \t]+] + * + * NB: + * The buffer sent is (almost) always modified. + */ +static int +parse_automount_spec(char *s, char **fstyp, char **srcp, char **optsp) +{ + int err; + char *cp; + char *fsty, *src, *opts; + + err = 0; + + /* + * Eat leading white. + */ + while (*s && *s == ' ' && *s == '\t') + s++; + /* + * Get fstype. + */ + fsty = cp = s; + while (*cp && + *cp != ':' && + *cp != ' ' && + *cp != '\t' && + *cp != '\r' && + *cp != '\n') + cp++; + if (fsty == cp || *cp != ':') + goto error; + *cp++ = '\0'; + + s = cp; + /* + * Eat leading white. + */ + while (*s && *s == ' ' && *s == '\t') + s++; + /* + * Get source. + */ + src = cp = s; + while (*cp && + *cp != ' ' && + *cp != '\t' && + *cp != '\r' && + *cp != '\n') + cp++; + if (src == cp) + goto error; + if (*cp) + *cp++ = '\0'; + + s = cp; + /* + * Eat leading white. + */ + while (*s && *s == ' ' && *s == '\t') + s++; + /* + * Get opts. + */ + opts = cp = s; + while (*cp && + *cp != ' ' && + *cp != '\t' && + *cp != '\r' && + *cp != '\n') + cp++; + if (opts == cp) + opts = NULL; + if (*cp) + *cp++ = '\0'; + + if (*cp) + goto error; + + *fstyp = fsty; + *srcp = src; + *optsp = opts; + return 0; + +error: + return -EINVAL; +} + +/* + * Parse (and strip) system mount options. + */ +static char * +parse_opts(char *opts, unsigned *flagsp) +{ + unsigned flags; + char *src, *dst; + char *cp; + + flags = 0; + src = dst = opts; + for (;;) { + cp = src; + while (*cp && *cp != ',') + cp++; + if (src + 2 == cp && strncmp(src, "rw", 2) == 0) { + /* + * Do nothing. This is the default. + */ + src += 2; + } else if (src + 2 == cp && strncmp(src, "ro", 2) == 0) { + /* + * Read-only. + */ + flags |= MOUNT_F_RO; + src += 2; + } + else if (src + 4 == cp && strncmp(src, "auto", 4) == 0) { + /* + * Enable automounts. + */ + flags |= MOUNT_F_AUTO; + src += 4; + } + if (src < cp) { + /* + * Copy what we didn't consume. + */ + if (dst != opts) + *dst++ = ','; + do + *dst++ = *src++; + while (src != cp); + } + if (!*src) + break; + *dst = '\0'; + src++; /* skip comma */ + } + *dst = '\0'; + + *flagsp = flags; + return opts; +} + +/* + * Attempt automount over the given directory. + */ +int +_sysio_automount(struct pnode *mntpno) +{ + int err; + struct inode *ino; + struct intnl_stat stbuf; + struct iovec iovec; + struct ioctx iocontext; + struct intnl_xtvec xtvec; + ssize_t cc; + char *fstype, *source, *opts; + unsigned flags; + struct fsswent *fssw; + struct mount *mnt; + + /* + * Revalidate -- Paranoia. + */ + err = _sysio_p_validate(mntpno, NULL, NULL); + if (err) + return err; + + /* + * Read file content. + */ + ino = mntpno->p_base->pb_ino; + err = (*ino->i_ops.inop_getattr)(mntpno, ino, &stbuf); + if (err) + return err; + if (stbuf.st_size > 64 * 1024) { + /* + * Let's be reasonable. + */ + return -EINVAL; + } + iovec.iov_base = malloc(stbuf.st_size + 1); + if (!iovec.iov_base) + return -ENOMEM; + iovec.iov_len = stbuf.st_size; + err = _sysio_open(mntpno, O_RDONLY, 0); + if (err) + goto out; + xtvec.xtv_off = 0; + xtvec.xtv_len = stbuf.st_size; + IOCTX_INIT(&iocontext, + 1, + (ioid_t )&iocontext, + 0, + ino, + &iovec, 1, + &xtvec, 1); + _sysio_ioctx_enter(&iocontext); + err = (*ino->i_ops.inop_read)(ino, &iocontext); + if (err) { + _sysio_ioctx_complete(&iocontext); + (void )(*ino->i_ops.inop_close)(ino); + goto out; + } + cc = _sysio_ioctx_wait(&iocontext); + err = (*ino->i_ops.inop_close)(ino); + if (err) + goto out; + if (cc < 0) { + err = (int )cc; + goto out; + } + ((char *)iovec.iov_base)[cc] = '\0'; + + /* + * Parse. + */ + err = parse_automount_spec(iovec.iov_base, &fstype, &source, &opts); + if (err) + goto out; + flags = 0; + if (opts) + opts = parse_opts(opts, &flags); + + /* + * Find the file system switch entry specified. + */ + fssw = _sysio_fssw_lookup(fstype); + if (!fssw) { + err = -ENODEV; + goto out; + } + + /* + * Do the deed. + */ + P_REF(mntpno->p_parent); + err = + (*fssw->fssw_ops.fsswop_mount)(source, + flags, + opts, + mntpno->p_parent, + &mnt); + if (err) + P_RELE(mntpno->p_parent); + +out: + if (iovec.iov_base) + free(iovec.iov_base); + return err; +} +#endif diff --git a/libsysio/src/namei.c b/libsysio/src/namei.c new file mode 100644 index 0000000..2d2e905 --- /dev/null +++ b/libsysio/src/namei.c @@ -0,0 +1,471 @@ +/* + * This Cplant(TM) source code is the property of Sandia National + * Laboratories. + * + * This Cplant(TM) source code is copyrighted by Sandia National + * Laboratories. + * + * The redistribution of this Cplant(TM) source code is subject to the + * terms of the GNU Lesser General Public License + * (see cit/LGPL or http://www.gnu.org/licenses/lgpl.html) + * + * Cplant(TM) Copyright 1998-2003 Sandia Corporation. + * Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive + * license for use of this work by or on behalf of the US Government. + * Export of this program may require a license from the United States + * Government. + */ + +/* + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Questions or comments about this library should be sent to: + * + * Lee Ward + * Sandia National Laboratories, New Mexico + * P.O. Box 5800 + * Albuquerque, NM 87185-1110 + * + * lee@sandia.gov + */ + +#if defined(AUTOMOUNT_FILE_NAME) && defined(__linux__) +#define _BSD_SOURCE +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "sysio.h" +#include "mount.h" +#include "inode.h" + +/* + * Parse next component in path. + */ +#ifndef AUTOMOUNT_FILE_NAME +static +#endif +void +_sysio_next_component(const char *path, struct qstr *name) +{ + while (*path == PATH_SEPARATOR) + path++; + name->name = path; + name->len = 0; + name->hashval = 0; + while (*path && *path != PATH_SEPARATOR) { + name->hashval = + 37 * name->hashval + *path++; + name->len++; + } +} + +/* + * Given parent, look up component. + */ +static int +lookup(struct pnode *parent, + struct qstr *name, + struct pnode **pnop, + struct intent *intnt, + const char *path) +{ + struct pnode *pno; + int err; + + if (!parent->p_base->pb_ino) + return -ENOTDIR; + + /* + * Short-circuit `.' and `..'; We don't cache those. + */ + pno = NULL; + if (name->len == 1 && name->name[0] == '.') + pno = parent; + else if (name->len == 2 && name->name[0] == '.' && name->name[1] == '.') + pno = parent->p_parent; + if (pno) + P_REF(pno); + else { + /* + * Get cache entry then. + */ + err = _sysio_p_find_alias(parent, name, &pno); + if (err) + return err; + } + + /* + * While covered, move to the covering node. + */ + while (pno->p_cover && pno->p_cover != pno) { + struct pnode *cover; + + cover = pno->p_cover; + P_REF(cover); + P_RELE(pno); + pno = cover; + } + + *pnop = pno; + + /* + * (Re)validate the pnode. + */ + err = _sysio_p_validate(pno, intnt, path); + if (err) + return err; + + return 0; +} + +/* + * The meat. Walk an absolute or relative path, looking up each + * component. Various flags in the nameidata argument govern actions + * and return values/state. They are: + * + * ND_NOFOLLOW symbolic links are not followed + * ND_NEGOK if terminal/leaf does not exist, return + * path node (alias) anyway. + */ +int +_sysio_path_walk(struct pnode *parent, struct nameidata *nd) +{ + int err; + const char *path; + struct qstr this, next; + struct inode *ino; + + /* + * NULL path? + */ + if (!nd->nd_path) + return -EFAULT; + + /* + * Empty path? + */ + if (!*nd->nd_path) + return -ENOENT; + + /* + * Leading slash? + */ + if (*nd->nd_path == PATH_SEPARATOR) { + /* + * Make parent the root of the name space. + */ + parent = nd->nd_root; + } + + /* + * (Re)Validate the parent. + */ + err = _sysio_p_validate(parent, NULL, NULL); + if (err) + return err; + + /* + * Prime everything for the loop. Will need another reference to the + * initial directory. It'll be dropped later. + */ + nd->nd_pno = parent; + P_REF(nd->nd_pno); + _sysio_next_component(nd->nd_path, &next); + path = next.name; + parent = NULL; + err = 0; + + /* + * Derecurse the path tree-walk. + */ + for (;;) { + ino = nd->nd_pno->p_base->pb_ino; + if (S_ISLNK(ino->i_mode) && + (next.len || !(nd->nd_flags & ND_NOFOLLOW))) { + char *lpath; + ssize_t cc; + struct nameidata nameidata; + + if (nd->nd_slicnt >= MAX_SYMLINK) { + err = -ELOOP; + break; + } + + /* + * Follow symbolic link. + */ + lpath = malloc(MAXPATHLEN + 1); + if (!lpath) { + err = -ENOMEM; + break; + } + cc = + ino->i_ops.inop_readlink(nd->nd_pno, + lpath, + MAXPATHLEN); + if (cc < 0) { + free(lpath); + err = (int )cc; + break; + } + lpath[cc] = '\0'; /* NUL term */ + /* + * Handle symbolic links with recursion. Yuck! + */ + ND_INIT(&nameidata, + (nd->nd_flags | ND_NEGOK), + lpath, + nd->nd_root, + nd->nd_intent); + nameidata.nd_slicnt = nd->nd_slicnt + 1; + err = + _sysio_path_walk(nd->nd_pno->p_parent, &nameidata); + free(lpath); + if (err) + break; + P_RELE(nd->nd_pno); + nd->nd_pno = nameidata.nd_pno; + ino = nd->nd_pno->p_base->pb_ino; + } +#ifdef AUTOMOUNT_FILE_NAME + else if (ino && + S_ISDIR(ino->i_mode) && + (nd->nd_pno->p_mount->mnt_flags & MOUNT_F_AUTO) && + nd->nd_amcnt < MAX_MOUNT_DEPTH && + ino->i_mode & S_ISUID) { + struct pnode *pno; + + /* + * We're committed to a lookup. It's time to see if + * we're going to do it in an automount-point and + * arrange the mount if so. + */ + assert(!nd->nd_pno->p_cover); + err = + lookup(nd->nd_pno, + &_sysio_mount_file_name, + &pno, + NULL, + NULL); + if (pno) + P_RELE(pno); + if (!err && _sysio_automount(pno) == 0) { + struct pnode *root; + + /* + * All went well. Need to switch + * parent pno and ino to the + * root of the newly mounted sub-tree. + * + * NB: + * We don't recurseively retry these + * things. It's OK to have the new root + * be an automount-point but it's going + * to take another lookup to accomplish it. + * The alternative could get us into an + * infinite loop. + */ + root = nd->nd_pno->p_cover; + assert(root); + P_RELE(nd->nd_pno); + nd->nd_pno = root; +#if 0 + P_REF(nd->nd_pno); +#endif + ino = nd->nd_pno->p_base->pb_ino; + assert(ino); + + /* + * Must send the intent-path again. + */ + path = nd->nd_path; + nd->nd_amcnt++; + + /* + * Must go back top and retry with this + * new pnode as parent. + */ + continue; + } + err = 0; /* it never happened */ + } +#endif + + /* + * Set up for next component. + */ + this = next; + if (path) + path = this.name; + if (!this.len) + break; + if (!ino) { + /* + * Should only be here if final component was + * target of a symlink. + */ + nd->nd_path = this.name + this.len; + err = -ENOENT; + break; + } + nd->nd_path = this.name + this.len; + _sysio_next_component(nd->nd_path, &next); + parent = nd->nd_pno; + nd->nd_pno = NULL; + + /* + * Parent must be a directory. + */ + if (ino && !S_ISDIR(ino->i_mode)) { + err = -ENOTDIR; + break; + } + + /* + * The extra path arg is passed only on the first lookup in the + * walk as we cross into each file system, anew. The intent is + * passed both on the first lookup and when trying to look up + * the final component -- Of the original path, not on the + * file system. + * + * Confused? Me too and I came up with this weirdness. It's + * hints to the file system drivers. Read on. + * + * The first lookup will give everything one needs to ready + * everything for the entire operation before the path is + * walked. The file system driver knows it's the first lookup + * in the walk because it has both the path and the intent. + * + * Alternatively, one could split the duties; The first lookup + * can be used to prime the file system inode cache with the + * interior nodes we'll want in the path-walk. Then, when + * looking up the last component, ready everything for the + * operations(s) to come. The file system driver knows it's + * the last lookup in the walk because it has the intent, + * again, but without the path. + * + * One special case; If we were asked to look up a single + * component, we treat it as the last component. The file + * system driver never sees the extra path argument. It should + * be noted that the driver always has the fully qualified + * path, on the target file system, available to it for any + * node it is looking up, including the last, via the base + * path node and it's ancestor chain. + */ + err = + lookup(parent, + &this, + &nd->nd_pno, + (path || !next.len) + ? nd->nd_intent + : NULL, + (path && next.len) ? path : NULL); + if (err) { + if (err == -ENOENT && + !next.len && + (nd->nd_flags & ND_NEGOK)) + err = 0; + break; + } + path = NULL; /* Stop that! */ + if ((parent->p_mount->mnt_fs != + nd->nd_pno->p_mount->mnt_fs)) { + /* + * Crossed into a new fs. We'll want the next lookup + * to include the path again. + */ + path = nd->nd_path; + } + + /* + * Release the parent. + */ + P_RELE(parent); + parent = NULL; + } + + /* + * Trailing separators cause us to break from the loop with + * a parent set but no pnode. Check for that. + */ + if (!nd->nd_pno) { + nd->nd_pno = parent; + parent = NULL; + /* + * Make sure the last processed component was a directory. The + * trailing slashes are illegal behind anything else. + */ + if (!(err || S_ISDIR(nd->nd_pno->p_base->pb_ino->i_mode))) + err = -ENOTDIR; + } + + /* + * Drop reference to parent if set. Either we have a dup of the original + * parent or an intermediate reference. + */ + if (parent) + P_RELE(parent); + + /* + * On error, we will want to drop our reference to the current + * path node if at end. + */ + if (err && nd->nd_pno) { + P_RELE(nd->nd_pno); + nd->nd_pno = NULL; + } + + return err; +} + +#ifdef CPLANT_YOD +/* + * for backward compatibility w/protocol switch + * remove everything up to the first ':' + * fortran libs prepend cwd to path, so not much choice + */ +#define STRIP_PREFIX(p) strchr(p,':') ? strchr(p,':')+1 : p +#else +#define STRIP_PREFIX(p) p +#endif + +/* + * Expanded form of the path-walk routine, with the common arguments, builds + * the nameidata bundle and calls path-walk. + */ +int +_sysio_namei(struct pnode *parent, + const char *path, + unsigned flags, + struct intent *intnt, + struct pnode **pnop) +{ + struct nameidata nameidata; + int err; + + ND_INIT(&nameidata, flags, STRIP_PREFIX(path), _sysio_root, intnt); + err = _sysio_path_walk(parent, &nameidata); + if (!err) + *pnop = nameidata.nd_pno; + return err; +} diff --git a/libsysio/src/open.c b/libsysio/src/open.c new file mode 100644 index 0000000..a7c3127 --- /dev/null +++ b/libsysio/src/open.c @@ -0,0 +1,303 @@ +/* + * This Cplant(TM) source code is the property of Sandia National + * Laboratories. + * + * This Cplant(TM) source code is copyrighted by Sandia National + * Laboratories. + * + * The redistribution of this Cplant(TM) source code is subject to the + * terms of the GNU Lesser General Public License + * (see cit/LGPL or http://www.gnu.org/licenses/lgpl.html) + * + * Cplant(TM) Copyright 1998-2003 Sandia Corporation. + * Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive + * license for use of this work by or on behalf of the US Government. + * Export of this program may require a license from the United States + * Government. + */ + +/* + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Questions or comments about this library should be sent to: + * + * Lee Ward + * Sandia National Laboratories, New Mexico + * P.O. Box 5800 + * Albuquerque, NM 87185-1110 + * + * lee@sandia.gov + */ + +/* + * Incorporate the GNU flags for open if we can. + */ +#define _GNU_SOURCE + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "sysio.h" +#include "inode.h" +#include "file.h" +#include "fs.h" +#include "mount.h" +#include "sysio-symbols.h" + +#include "sysio-symbols.h" + +/* + * Open file support. + */ + +mode_t _sysio_umask = 0; /* process umask. */ + +/* + * Internal form of open. + */ +int +_sysio_open(struct pnode *pno, int flags, mode_t mode) +{ + int ro; + int w; + int err; + struct inode *ino; + + ro = IS_RDONLY(pno, pno->p_base->pb_ino); + w = flags & (O_WRONLY|O_RDWR); + if (w == (O_WRONLY|O_RDWR)) { + /* + * Huh? + */ + return -EINVAL; + } + if (w && ro) + return -EROFS; + ino = pno->p_base->pb_ino; + if ((flags & O_CREAT) && !ino) { + struct pnode *parent; + + /* + * Must create it. + */ + if (ro) + return -EROFS; + parent = pno->p_parent; + err = _sysio_p_validate(parent, NULL, NULL); + if (!err) { + ino = parent->p_base->pb_ino; + assert(ino); + err = + !IS_RDONLY(parent, ino) + ? (*ino->i_ops.inop_open)(pno, flags, mode) + : -EROFS; + } + } else if ((flags & (O_CREAT|O_EXCL)) == (O_CREAT|O_EXCL)) + err = -EEXIST; + else if (!ino) + err = _sysio_p_validate(pno, NULL, NULL); + else { + /* + * Simple open of pre-existing file. + */ + err = (*ino->i_ops.inop_open)(pno, flags, mode); + } + + return err; +} + +#undef open + +int +SYSIO_INTERFACE_NAME(open)(const char *path, int flags, ...) +{ + mode_t mode; + unsigned ndflags; + struct intent intent; + int rtn; + struct pnode *pno; + struct file *fil; + SYSIO_INTERFACE_DISPLAY_BLOCK; + + SYSIO_INTERFACE_ENTER; + /* + * Get mode argument and determine parameters for namei + */ + mode = 0; + ndflags = 0; + intent.int_opmask = INT_OPEN; + if (flags & O_CREAT) { + va_list ap; + + /* + * Set ndflags to indicate return of negative alias is OK. + */ + ndflags |= ND_NEGOK; + + /* + * Will need mode too. + */ + va_start(ap, flags); + mode = +#ifndef REDSTORM + va_arg(ap, mode_t); +#else + va_arg(ap, int); +#endif + va_end(ap); + mode &= ~(_sysio_umask & 0777) | 07000; /* apply umask */ + + if (flags & O_EXCL) { + /* + * Tell others we intend to create this file. + */ + intent.int_opmask |= INT_CREAT; + } + } +#ifdef O_NOFOLLOW + if (flags & O_NOFOLLOW) + ndflags |= ND_NOFOLLOW; +#endif + + /* + * Find the file. + */ + fil = NULL; + INTENT_INIT(&intent, intent.int_opmask, &mode, &flags); + pno = NULL; + rtn = _sysio_namei(_sysio_cwd, path, ndflags, &intent, &pno); + if (rtn) + goto error; + /* + * Ask for the open/creat. + */ + rtn = _sysio_open(pno, flags, mode); + if (rtn) + goto error; + /* + * Get a file descriptor. + */ + fil = _sysio_fnew(pno->p_base->pb_ino, flags); + if (!fil) { + rtn = -ENOMEM; + goto error; + } + rtn = _sysio_fd_set(fil, -1); + if (rtn < 0) + goto error; + + P_RELE(pno); + + SYSIO_INTERFACE_RETURN(rtn, 0); + +error: + if (fil) + F_RELE(fil); + if (pno) + P_RELE(pno); + SYSIO_INTERFACE_RETURN(-1, rtn); +} + +#ifdef __GLIBC__ +#undef __open +sysio_sym_weak_alias(SYSIO_INTERFACE_NAME(open), __open) +#undef open64 +sysio_sym_weak_alias(SYSIO_INTERFACE_NAME(open), SYSIO_INTERFACE_NAME(open64)) +#undef __open64 +sysio_sym_weak_alias(SYSIO_INTERFACE_NAME(open), __open64) +#endif + +#ifdef REDSTORM +#undef __libc_open64 +sysio_sym_weak_alias(SYSIO_INTERFACE_NAME(open), __libc_open64) +#endif + +#ifdef BSD +#undef _open +sysio_sym_weak_alias(SYSIO_INTERFACE_NAME(open), _open) +#endif + +int +SYSIO_INTERFACE_NAME(close)(int fd) +{ + int err; + SYSIO_INTERFACE_DISPLAY_BLOCK; + + SYSIO_INTERFACE_ENTER; + err = _sysio_fd_close(fd); + SYSIO_INTERFACE_RETURN(err ? -1 : 0, err); +} + +#ifdef __GLIBC__ +#undef __close +sysio_sym_weak_alias(SYSIO_INTERFACE_NAME(close), __close) +#endif + +#ifdef BSD +#undef _close +sysio_sym_weak_alias(SYSIO_INTERFACE_NAME(close), _close) +#endif + +int +SYSIO_INTERFACE_NAME(creat)(const char *path, mode_t mode) +{ + + return open(path, O_CREAT|O_WRONLY|O_TRUNC, mode); +} + +#ifdef __GLIBC__ +#undef __creat +sysio_sym_weak_alias(SYSIO_INTERFACE_NAME(creat), __creat) +#undef creat64 +#ifndef HAVE_LUSTRE_HACK +sysio_sym_weak_alias(SYSIO_INTERFACE_NAME(creat), SYSIO_INTERFACE_NAME(creat64)) +#else +/* XXX workaround SuSE SLES 8, glibc-2.2.5 */ +sysio_sym_strong_alias(SYSIO_INTERFACE_NAME(creat), SYSIO_INTERFACE_NAME(creat64)) +#endif +#undef __creat64 +sysio_sym_weak_alias(SYSIO_INTERFACE_NAME(creat), __creat64) +#endif + +#ifdef REDSTORM +#undef __libc_creat +sysio_sym_weak_alias(SYSIO_INTERFACE_NAME(creat), __libc_creat) +#endif + +#ifdef BSD +#undef _creat +sysio_sym_weak_alias(SYSIO_INTERFACE_NAME(creat), _creat) +#endif + +mode_t +SYSIO_INTERFACE_NAME(umask)(mode_t mask) +{ + mode_t omask; + + omask = _sysio_umask; + _sysio_umask = mask & 0777; + return omask; +} + +#ifdef REDSTORM +#undef __umask +sysio_sym_weak_alias(SYSIO_INTERFACE_NAME(umask), __umask) +#endif diff --git a/libsysio/src/readlink.c b/libsysio/src/readlink.c new file mode 100644 index 0000000..7053c62 --- /dev/null +++ b/libsysio/src/readlink.c @@ -0,0 +1,83 @@ +/* + * This Cplant(TM) source code is the property of Sandia National + * Laboratories. + * + * This Cplant(TM) source code is copyrighted by Sandia National + * Laboratories. + * + * The redistribution of this Cplant(TM) source code is subject to the + * terms of the GNU Lesser General Public License + * (see cit/LGPL or http://www.gnu.org/licenses/lgpl.html) + * + * Cplant(TM) Copyright 1998-2004 Sandia Corporation. + * Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive + * license for use of this work by or on behalf of the US Government. + * Export of this program may require a license from the United States + * Government. + */ + +/* + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Questions or comments about this library should be sent to: + * + * Lee Ward + * Sandia National Laboratories, New Mexico + * P.O. Box 5800 + * Albuquerque, NM 87185-1110 + * + * lee@sandia.gov + */ + +#include +#include +#include +#include +#include + +#include "sysio.h" +#include "inode.h" +#include "sysio-symbols.h" + +int +SYSIO_INTERFACE_NAME(readlink)(const char *path, char *buf, size_t bufsiz) +{ + struct intent intent; + int err; + struct pnode *pno; + struct inode *ino; + SYSIO_INTERFACE_DISPLAY_BLOCK; + + SYSIO_INTERFACE_ENTER; + INTENT_INIT(&intent, INT_GETATTR, NULL, NULL); + err = _sysio_namei(_sysio_cwd, path, ND_NOFOLLOW, &intent, &pno); + if (err) + goto out; + ino = pno->p_base->pb_ino; + err = (*ino->i_ops.inop_readlink)(pno, buf, bufsiz); + if (err) + goto error; + +error: + P_RELE(pno); +out: + SYSIO_INTERFACE_RETURN(err, err >= 0 ? 0 : err); +} + +#ifdef REDSTORM +#undef __readlink +sysio_sym_weak_alias(SYSIO_INTERFACE_NAME(readlink), + PREPEND(__, SYSIO_INTERFACE_NAME(readlink))) +#endif diff --git a/libsysio/src/rename.c b/libsysio/src/rename.c new file mode 100644 index 0000000..167c74f --- /dev/null +++ b/libsysio/src/rename.c @@ -0,0 +1,181 @@ +/* + * This Cplant(TM) source code is the property of Sandia National + * Laboratories. + * + * This Cplant(TM) source code is copyrighted by Sandia National + * Laboratories. + * + * The redistribution of this Cplant(TM) source code is subject to the + * terms of the GNU Lesser General Public License + * (see cit/LGPL or http://www.gnu.org/licenses/lgpl.html) + * + * Cplant(TM) Copyright 1998-2003 Sandia Corporation. + * Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive + * license for use of this work by or on behalf of the US Government. + * Export of this program may require a license from the United States + * Government. + */ + +/* + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Questions or comments about this library should be sent to: + * + * Lee Ward + * Sandia National Laboratories, New Mexico + * P.O. Box 5800 + * Albuquerque, NM 87185-1110 + * + * lee@sandia.gov + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "sysio.h" +#include "mount.h" +#include "inode.h" + +int +SYSIO_INTERFACE_NAME(rename)(const char *oldpath, const char *newpath) +{ + struct intent intent; + int err; + struct pnode *old, *new; + struct pnode_base *nxtpb, *pb; + struct intnl_stat ostbuf, nstbuf; + SYSIO_INTERFACE_DISPLAY_BLOCK; + + SYSIO_INTERFACE_ENTER; + /* + * Resolve oldpath to a path node. + */ + INTENT_INIT(&intent, INT_UPDPARENT, NULL, NULL); + err = _sysio_namei(_sysio_cwd, oldpath, 0, &intent, &old); + if (err) + goto error3; + /* + * Resolve newpath to a path node. + */ + INTENT_INIT(&intent, INT_UPDPARENT, NULL, NULL); + err = _sysio_namei(_sysio_cwd, newpath, ND_NEGOK, &intent, &new); + if (err && !new) + goto error2; + + if (old->p_mount->mnt_root == old || old->p_cover || + new->p_mount->mnt_root == new) { + err = -EBUSY; + goto error1; + } + + if (old->p_mount->mnt_fs != new->p_mount->mnt_fs) { + /* + * Oops. They're trying to move it across file systems. + */ + err = -EXDEV; + goto error1; + } + + /* + * Make sure the old pnode can't be found in the ancestor chain + * for the new. If it can, they are trying to move into a subdirectory + * of the old. + */ + nxtpb = new->p_base; + do { + pb = nxtpb; + nxtpb = pb->pb_parent; + if (pb == old->p_base) { + err = -EINVAL; + goto error1; + } + } while (nxtpb); + + while (new->p_base->pb_ino) { + /* + * Existing entry. We're replacing the new. Make sure that's + * ok. + */ + err = + old->p_base->pb_ino->i_ops.inop_getattr(old, NULL, &ostbuf); + if (err) + goto error1; + err = + new->p_base->pb_ino->i_ops.inop_getattr(new, NULL, &nstbuf); + if (err) { + if (err != ENOENT) + goto error1; + /* + * Rats! It disappeared beneath us. + */ + (void )_sysio_p_validate(new, NULL, NULL); + continue; + } + if (S_ISDIR(ostbuf.st_mode)) { + if (!S_ISDIR(nstbuf.st_mode)) { + err = -ENOTDIR; + goto error1; + } + if (nstbuf.st_nlink > 2) { + err = -ENOTEMPTY; + goto error1; + } + } else if (S_ISDIR(nstbuf.st_mode)) { + err = -EEXIST; + goto error1; + } + break; + } + + /* + * It's not impossible to clean up the altered name space after + * a rename. However, it is onerous and I don't want to do it right + * now. If it becomes an issue, we can do it later. For now, I've + * elected to use the semantic that says, basically, the entire + * sub-tree must be unreferenced. That's per POSIX, but it's a nasty + * this to do to the caller. + */ + if (_sysio_p_prune(new) != 1) { + err = -EBUSY; + goto error1; + } + err = old->p_base->pb_ino->i_ops.inop_rename(old, new); + if (err) + goto error1; + /* + * Reflect the successful rename in the active name space graph. + */ + if (new->p_base->pb_ino) + I_GONE(new->p_base->pb_ino); + new->p_base->pb_ino = old->p_base->pb_ino; + I_REF(new->p_base->pb_ino); + +error1: + P_RELE(new); +error2: + P_RELE(old); +error3: + if (err) + goto out; + _sysio_p_gone(old); /* kill it! */ +out: + SYSIO_INTERFACE_RETURN(err ? -1 : 0, err); +} diff --git a/libsysio/src/rmdir.c b/libsysio/src/rmdir.c new file mode 100644 index 0000000..cbc7632 --- /dev/null +++ b/libsysio/src/rmdir.c @@ -0,0 +1,97 @@ +/* + * This Cplant(TM) source code is the property of Sandia National + * Laboratories. + * + * This Cplant(TM) source code is copyrighted by Sandia National + * Laboratories. + * + * The redistribution of this Cplant(TM) source code is subject to the + * terms of the GNU Lesser General Public License + * (see cit/LGPL or http://www.gnu.org/licenses/lgpl.html) + * + * Cplant(TM) Copyright 1998-2003 Sandia Corporation. + * Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive + * license for use of this work by or on behalf of the US Government. + * Export of this program may require a license from the United States + * Government. + */ + +/* + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Questions or comments about this library should be sent to: + * + * Lee Ward + * Sandia National Laboratories, New Mexico + * P.O. Box 5800 + * Albuquerque, NM 87185-1110 + * + * lee@sandia.gov + */ + +#include +#include +#include +#include +#include + +#include "sysio.h" +#include "inode.h" +#include "fs.h" +#include "mount.h" +#include "sysio-symbols.h" + +int +SYSIO_INTERFACE_NAME(rmdir)(const char *path) +{ + struct intent intent; + int err; + struct pnode *pno; + struct inode *ino; + SYSIO_INTERFACE_DISPLAY_BLOCK; + + SYSIO_INTERFACE_ENTER; + INTENT_INIT(&intent, INT_UPDPARENT, NULL, NULL); + err = _sysio_namei(_sysio_cwd, path, 0, &intent, &pno); + if (err) + goto out; + if (IS_RDONLY(pno, pno->p_base->pb_ino)) { + err = -EROFS; + goto error; + } + if (pno->p_ref > 1) { + err = -EBUSY; + goto error; + } + err = pno->p_base->pb_ino->i_ops.inop_rmdir(pno); + if (err) + goto error; + /* + * Invalidate the path-base node and kill the i-node. + */ + ino = pno->p_base->pb_ino; + pno->p_base->pb_ino = NULL; + I_GONE(ino); +error: + P_RELE(pno); +out: + SYSIO_INTERFACE_RETURN(err ? -1 : 0, err); +} + +#ifdef REDSTORM +#undef __rmdir +sysio_sym_weak_alias(SYSIO_INTERFACE_NAME(rmdir), + PREPEND(__, SYSIO_INTERFACE_NAME(rmdir))) +#endif diff --git a/libsysio/src/rw.c b/libsysio/src/rw.c new file mode 100644 index 0000000..ad103b8 --- /dev/null +++ b/libsysio/src/rw.c @@ -0,0 +1,1325 @@ +/* + * This Cplant(TM) source code is the property of Sandia National + * Laboratories. + * + * This Cplant(TM) source code is copyrighted by Sandia National + * Laboratories. + * + * The redistribution of this Cplant(TM) source code is subject to the + * terms of the GNU Lesser General Public License + * (see cit/LGPL or http://www.gnu.org/licenses/lgpl.html) + * + * Cplant(TM) Copyright 1998-2004 Sandia Corporation. + * Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive + * license for use of this work by or on behalf of the US Government. + * Export of this program may require a license from the United States + * Government. + */ + +/* + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Questions or comments about this library should be sent to: + * + * Lee Ward + * Sandia National Laboratories, New Mexico + * P.O. Box 5800 + * Albuquerque, NM 87185-1110 + * + * lee@sandia.gov + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "sysio.h" +#include "file.h" +#include "inode.h" +#include "xtio.h" + +#include "sysio-symbols.h" + +#define IIOXOP_READ(ino) (ino)->i_ops.inop_read, 0 +#define IIOXOP_WRITE(ino) (ino)->i_ops.inop_write, 1 + +/* + * Decoding the interface routine names: + * + * Much of this carries legacy from the POSIX world and the Intel ASCI + * Red programming environment. Routine names are composed of prefix, + * basic POSIX names, and postfix. The basic POSIX names are read and write. + * Prefixes, left-to-right: + * + * - 'i' -- asynchronous operation (from ASCI Red) + * - 'p' -- positional (POSIX) + * Posfixes, only one: + * - 'v' -- vectored (POSIX) + * - 'x' -- extent-based (new for Red Storm) + * + * All valid combinations are available and symmetric. + */ + +/* + * Post op using iovec with regions specified by the passed extent vector. + * + * NOTE: There are enough parameters that we should really consider + * passing them in a structure. + */ +static int +_sysio_iiox(int (*f)(struct inode *, struct ioctx *), + int wr, + struct file *fil, + const struct iovec *iov, + size_t iov_count, + void (*iov_free)(struct ioctx *), + const struct intnl_xtvec *xtv, + size_t xtv_count, + void (*xtv_free)(struct ioctx *), + void (*completio)(struct ioctx *, void *), + struct ioctx **ioctxp) +{ + struct inode *ino; + ssize_t cc; + struct ioctx *ioctx; + int err; + struct ioctx_callback *cb; + + /* + * Check that it was opened with flags supporting the operation. + */ + if (!(wr + ? (fil->f_flags & (O_RDWR | O_WRONLY)) + : !(fil->f_flags & O_WRONLY))) + return -EBADF; + + ino = fil->f_ino; + if (!ino) { + /* + * Huh? It's dead. + */ + return -EBADF; + } + cc = + _sysio_validx(xtv, xtv_count, + iov, iov_count, +#if _LARGEFILE64_SOURCE && defined(O_LARGEFILE) + (fil->f_flags & O_LARGEFILE) == 0 + ? LONG_MAX + : +#endif + _SYSIO_OFF_T_MAX); + if (cc < 0) + return cc; + ioctx = _sysio_ioctx_new(ino, wr, iov, iov_count, xtv, xtv_count); + if (!ioctx) + return -ENOMEM; + if ((iov_free && + (err = _sysio_ioctx_cb(ioctx, + (void (*)(struct ioctx *, + void *))iov_free, + NULL))) || + (xtv_free && + (err = _sysio_ioctx_cb(ioctx, + (void (*)(struct ioctx *, + void *))xtv_free, + NULL))) || + (completio && + (err = _sysio_ioctx_cb(ioctx, + (void (*)(struct ioctx *, + void *))completio, + fil))) || + (err = (*f)(ino, ioctx))) { + /* + * Release the callback queue. Don't want it run after all. + */ + while ((cb = ioctx->ioctx_cbq.tqh_first)) { + TAILQ_REMOVE(&ioctx->ioctx_cbq, + cb, + iocb_next); + _sysio_ioctx_cb_free(cb); + } + _sysio_ioctx_complete(ioctx); + return err; + } + *ioctxp = ioctx; + return 0; +} + +/* + * Sum iovec entries, returning total found or error if range of ssize_t would + * be exceeded. + */ +static ssize_t +_sysio_sum_iovec(const struct iovec *iov, int count) +{ + ssize_t tmp, cc; + + if (count <= 0) + return -EINVAL; + + cc = 0; + while (count--) { + tmp = cc; + cc += iov->iov_len; + if (tmp && iov->iov_len && cc <= tmp) + return -EINVAL; + iov++; + } + return cc; +} + +/* + * Asynch IO from/to iovec from/to current file offset. + */ +static int +_sysio_iiov(int (*f)(struct inode *, struct ioctx *), + int wr, + struct file *fil, + const struct iovec *iov, + int count, + void (*iov_free)(struct ioctx *), + struct intnl_xtvec *xtv, + void (*xtv_free)(struct ioctx *), + struct ioctx **ioctxp) +{ + ssize_t cc; + _SYSIO_OFF_T off; + int err; + + cc = _sysio_sum_iovec(iov, count); + if (cc < 0) + return (int )cc; + xtv->xtv_off = fil->f_pos; + xtv->xtv_len = cc; + off = xtv->xtv_off + xtv->xtv_len; + if (xtv->xtv_off && off <= xtv->xtv_off) { + /* + * Ouch! The IO vector specifies more bytes than + * are addressable. Trim the region to limit how + * much of the IO vector is finally transferred. + */ + xtv->xtv_len = _SYSIO_OFF_T_MAX - xtv->xtv_off; + } + err = + _sysio_iiox(f, + wr, + fil, + iov, count, iov_free, + xtv, 1, xtv_free, + (void (*)(struct ioctx *, void *))_sysio_fcompletio, + ioctxp); + if (err) + return err; + return 0; +} + +static void +free_xtv(struct ioctx *ioctx) +{ + + free((struct iovec *)ioctx->ioctx_xtv); + ioctx->ioctx_iov = NULL; +} + +ioid_t +SYSIO_INTERFACE_NAME(ireadv)(int fd, const struct iovec *iov, int count) +{ + struct file *fil; + struct intnl_xtvec *xtv; + struct ioctx *ioctx; + int err; + SYSIO_INTERFACE_DISPLAY_BLOCK; + + SYSIO_INTERFACE_ENTER; + fil = _sysio_fd_find(fd); + if (!fil) + SYSIO_INTERFACE_RETURN(IOID_FAIL, -EBADF); + + xtv = malloc(sizeof(struct intnl_xtvec)); + if (!xtv) + SYSIO_INTERFACE_RETURN(IOID_FAIL, -ENOMEM); + + err = + _sysio_iiov(IIOXOP_READ(fil->f_ino), + fil, + iov, count, NULL, + xtv, free_xtv, + &ioctx); + if (err) { + free(xtv); + SYSIO_INTERFACE_RETURN(IOID_FAIL, err); + } + SYSIO_INTERFACE_RETURN(ioctx->ioctx_id, 0); +} + +ssize_t +SYSIO_INTERFACE_NAME(readv)(int fd, const struct iovec *iov, int count) +{ + struct file *fil; + struct intnl_xtvec xtvector; + struct ioctx *ioctx; + int err; + ssize_t cc; + SYSIO_INTERFACE_DISPLAY_BLOCK; + + SYSIO_INTERFACE_ENTER; + fil = _sysio_fd_find(fd); + if (!fil) + SYSIO_INTERFACE_RETURN(-1, -EBADF); + + err = + _sysio_iiov(IIOXOP_READ(fil->f_ino), + fil, + iov, count, NULL, + &xtvector, NULL, + &ioctx); + if (!err && (cc = _sysio_ioctx_wait(ioctx)) < 0) + err = (int )cc; + + SYSIO_INTERFACE_RETURN(err ? -1 : cc, err); +} + +#if defined(__GLIBC__) +#undef __readv +sysio_sym_weak_alias(SYSIO_INTERFACE_NAME(readv), + PREPEND(__, SYSIO_INTERFACE_NAME(readv))) +#undef __libc_readv +sysio_sym_weak_alias(SYSIO_INTERFACE_NAME(readv), + PREPEND(__, SYSIO_INTERFACE_NAME(libc_readv))) +#endif + +static void +free_iov(struct ioctx *ioctx) +{ + + free((struct iovec *)ioctx->ioctx_iov); + ioctx->ioctx_iov = NULL; +} + +ioid_t +SYSIO_INTERFACE_NAME(iread)(int fd, void *buf, size_t count) +{ + struct iovec *iov; + struct file *fil; + struct intnl_xtvec *xtv; + struct ioctx *ioctx; + int err; + SYSIO_INTERFACE_DISPLAY_BLOCK; + + SYSIO_INTERFACE_ENTER; + fil = _sysio_fd_find(fd); + if (!fil) + SYSIO_INTERFACE_RETURN(IOID_FAIL, -EBADF); + + iov = malloc(sizeof(struct iovec)); + if (!iov) + SYSIO_INTERFACE_RETURN(IOID_FAIL, -ENOMEM); + + iov->iov_base = buf; + iov->iov_len = count; + xtv = malloc(sizeof(struct intnl_xtvec)); + if (!xtv) { + free(iov); + SYSIO_INTERFACE_RETURN(IOID_FAIL, -ENOMEM); + } + err = + _sysio_iiov(IIOXOP_READ(fil->f_ino), + fil, + iov, 1, free_iov, + xtv, free_xtv, + &ioctx); + if (err) { + free(xtv); + free(iov); + SYSIO_INTERFACE_RETURN(IOID_FAIL, err); + } + SYSIO_INTERFACE_RETURN(ioctx->ioctx_id, 0); +} + +ssize_t +SYSIO_INTERFACE_NAME(read)(int fd, void *buf, size_t count) +{ + struct file *fil; + struct iovec iovector; + struct intnl_xtvec xtvector; + int err; + struct ioctx *ioctx; + ssize_t cc; + SYSIO_INTERFACE_DISPLAY_BLOCK; + + SYSIO_INTERFACE_ENTER; + fil = _sysio_fd_find(fd); + if (!fil) + SYSIO_INTERFACE_RETURN(-1, -EBADF); + + iovector.iov_base = buf; + iovector.iov_len = count; + err = + _sysio_iiov(IIOXOP_READ(fil->f_ino), + fil, + &iovector, 1, NULL, + &xtvector, NULL, + &ioctx); + if (!err && (cc = _sysio_ioctx_wait(ioctx)) < 0) + err = (int )cc; + SYSIO_INTERFACE_RETURN(err ? -1 : cc, err); +} + +#ifdef __GLIBC__ +#undef __read +sysio_sym_weak_alias(SYSIO_INTERFACE_NAME(read), + PREPEND(__, SYSIO_INTERFACE_NAME(read))) +#undef __libc_read +sysio_sym_weak_alias(SYSIO_INTERFACE_NAME(read), + PREPEND(__, SYSIO_INTERFACE_NAME(libc_read))) +#endif + +/* + * Asynch IO between iovec and data at the given offset. + */ +static int +_sysio_ipiov(int (*f)(struct inode *, struct ioctx *), + int wr, + struct file *fil, + const struct iovec *iov, + int count, + void (*iov_free)(struct ioctx *), + _SYSIO_OFF_T off, + struct intnl_xtvec *xtv, + void (*xtv_free)(struct ioctx *), + struct ioctx **ioctxp) +{ + ssize_t cc; + int err; + + SYSIO_ENTER; + cc = _sysio_sum_iovec(iov, count); + if (cc < 0) { + SYSIO_LEAVE; + return (int )cc; + } + xtv->xtv_off = off, + xtv->xtv_len = cc; + err = + _sysio_iiox(f, + wr, + fil, + iov, count, iov_free, + xtv, 1, xtv_free, + NULL, + ioctxp); + SYSIO_LEAVE; + if (err) + return err; + return 0; +} + +static ioid_t +PREPEND(_, SYSIO_INTERFACE_NAME(ipreadv))(int fd, + const struct iovec *iov, + size_t count, + _SYSIO_OFF_T offset) +{ + struct file *fil; + struct intnl_xtvec *xtv; + struct ioctx *ioctx; + int err; + SYSIO_INTERFACE_DISPLAY_BLOCK; + + SYSIO_INTERFACE_ENTER; + fil = _sysio_fd_find(fd); + if (!fil) + SYSIO_INTERFACE_RETURN(IOID_FAIL, -EBADF); + + xtv = malloc(sizeof(struct intnl_xtvec)); + if (!xtv) + SYSIO_INTERFACE_RETURN(IOID_FAIL, -ENOMEM); + + err = + _sysio_ipiov(IIOXOP_READ(fil->f_ino), + fil, + iov, count, NULL, + offset, + xtv, free_xtv, + &ioctx); + if (err) { + free(xtv); + SYSIO_INTERFACE_RETURN(IOID_FAIL, err); + } + SYSIO_INTERFACE_RETURN(ioctx->ioctx_id, 0); +} + +#if _LARGEFILE64_SOURCE +#undef ipread64v +sysio_sym_weak_alias(PREPEND(_, SYSIO_INTERFACE_NAME(ipreadv)), + SYSIO_INTERFACE_NAME(ipread64v)) +#endif + +ioid_t +SYSIO_INTERFACE_NAME(ipreadv)(int fd, + const struct iovec *iov, + size_t count, + off_t offset) +{ + + return PREPEND(_, SYSIO_INTERFACE_NAME(ipreadv))(fd, + iov, + count, + offset); +} + +static ssize_t +PREPEND(_, SYSIO_INTERFACE_NAME(preadv))(int fd, + const struct iovec *iov, + size_t count, + _SYSIO_OFF_T offset) +{ + struct file *fil; + struct intnl_xtvec xtvector; + struct ioctx *ioctx; + int err; + ssize_t cc; + SYSIO_INTERFACE_DISPLAY_BLOCK; + + SYSIO_INTERFACE_ENTER; + fil = _sysio_fd_find(fd); + if (!fil) + SYSIO_INTERFACE_RETURN(-1, -EBADF); + + err = + _sysio_ipiov(IIOXOP_READ(fil->f_ino), + fil, + iov, count, NULL, + offset, + &xtvector, NULL, + &ioctx); + if (!err && (cc = _sysio_ioctx_wait(ioctx)) < 0) + err = (int )cc; + + SYSIO_INTERFACE_RETURN(err ? -1 : cc, err); +} + +#if _LARGEFILE64_SOURCE +#undef pread64v +sysio_sym_weak_alias(PREPEND(_, SYSIO_INTERFACE_NAME(preadv)), + SYSIO_INTERFACE_NAME(pread64v)) +#endif + +ssize_t +SYSIO_INTERFACE_NAME(preadv)(int fd, + const struct iovec *iov, + size_t count, + off_t offset) +{ + + return PREPEND(_, SYSIO_INTERFACE_NAME(preadv))(fd, + iov, + count, + offset); +} + +static ioid_t +PREPEND(_, SYSIO_INTERFACE_NAME(ipread))(int fd, + void *buf, + size_t count, + _SYSIO_OFF_T offset) +{ + struct file *fil; + struct intnl_xtvec *xtv; + struct iovec *iov; + struct ioctx *ioctx; + int err; + SYSIO_INTERFACE_DISPLAY_BLOCK; + + SYSIO_INTERFACE_ENTER; + fil = _sysio_fd_find(fd); + if (!fil) + SYSIO_INTERFACE_RETURN(IOID_FAIL, -EBADF); + + xtv = malloc(sizeof(struct intnl_xtvec)); + iov = malloc(sizeof(struct iovec)); + if (!(xtv && iov)) { + err = -ENOMEM; + goto error; + } + xtv->xtv_off = offset; + iov->iov_base = buf; + xtv->xtv_len = iov->iov_len = count; + err = + _sysio_ipiov(IIOXOP_READ(fil->f_ino), + fil, + iov, 1, free_iov, + offset, + xtv, free_xtv, + &ioctx); +error: + if (err) { + if (iov) + free(iov); + if (xtv) + free(xtv); + SYSIO_INTERFACE_RETURN(IOID_FAIL, err); + } + SYSIO_INTERFACE_RETURN(ioctx->ioctx_id, 0); +} + +#if _LARGEFILE64_SOURCE +#undef ipread64 +sysio_sym_weak_alias(PREPEND(_, SYSIO_INTERFACE_NAME(ipread)), + SYSIO_INTERFACE_NAME(ipread64)) +#endif + +ioid_t +SYSIO_INTERFACE_NAME(ipread)(int fd, + void *buf, + size_t count, + off_t offset) +{ + + return PREPEND(_, SYSIO_INTERFACE_NAME(ipread))(fd, + buf, + count, + offset); +} + +ssize_t +PREPEND(_, SYSIO_INTERFACE_NAME(pread))(int fd, + void *buf, + size_t count, + _SYSIO_OFF_T offset) +{ + struct file *fil; + struct intnl_xtvec xtvec; + struct iovec iovec; + struct ioctx *ioctx; + int err; + ssize_t cc; + SYSIO_INTERFACE_DISPLAY_BLOCK; + + SYSIO_INTERFACE_ENTER; + fil = _sysio_fd_find(fd); + if (!fil) + SYSIO_INTERFACE_RETURN(IOID_FAIL, -EBADF); + + xtvec.xtv_off = offset; + iovec.iov_base = buf; + xtvec.xtv_len = iovec.iov_len = count; + err = + _sysio_ipiov(IIOXOP_READ(fil->f_ino), + fil, + &iovec, 1, NULL, + offset, + &xtvec, NULL, + &ioctx); + if (!err && (cc = _sysio_ioctx_wait(ioctx)) < 0) + err = (int )cc; + + SYSIO_INTERFACE_RETURN(err ? -1 : cc, err); +} + +#if _LARGEFILE64_SOURCE +#undef pread64 +sysio_sym_weak_alias(PREPEND(_, SYSIO_INTERFACE_NAME(pread)), + SYSIO_INTERFACE_NAME(pread64)) +#if __GLIBC__ +#undef __pread64 +sysio_sym_weak_alias(PREPEND(_, SYSIO_INTERFACE_NAME(pread)), + PREPEND(__, SYSIO_INTERFACE_NAME(pread64))) +#undef __libc_pread64 +sysio_sym_weak_alias(PREPEND(_, SYSIO_INTERFACE_NAME(pread)), + PREPEND(__, SYSIO_INTERFACE_NAME(libc_pread64))) +#endif +#endif + +ssize_t +SYSIO_INTERFACE_NAME(pread)(int fd, void *buf, size_t count, off_t offset) +{ + + return PREPEND(_, SYSIO_INTERFACE_NAME(pread))(fd, + buf, + count, + offset); +} + +#if __GLIBC__ +#undef __pread +sysio_sym_weak_alias(SYSIO_INTERFACE_NAME(pread), + PREPEND(__, SYSIO_INTERFACE_NAME(pread))) +#undef __libc_pread +sysio_sym_weak_alias(SYSIO_INTERFACE_NAME(pread), + PREPEND(__, SYSIO_INTERFACE_NAME(libc_pread))) +#endif + +static ioid_t +PREPEND(_, SYSIO_INTERFACE_NAME(ireadx))(int fd, + const struct iovec *iov, + size_t iov_count, + const struct intnl_xtvec *xtv, + size_t xtv_count) +{ + struct file *fil; + int err; + struct ioctx *ioctx; + SYSIO_INTERFACE_DISPLAY_BLOCK; + + SYSIO_INTERFACE_ENTER; + fil = _sysio_fd_find(fd); + if (!(fil && xtv_count)) + SYSIO_INTERFACE_RETURN(IOID_FAIL, -EBADF); + + err = + _sysio_iiox(IIOXOP_READ(fil->f_ino), + fil, + iov, iov_count, NULL, + xtv, xtv_count, NULL, + NULL, + &ioctx); + + SYSIO_INTERFACE_RETURN(err ? IOID_FAIL : ioctx->ioctx_id, err); +} + +#if _LARGEFILE64_SOURCE +#undef iread64x +sysio_sym_weak_alias(PREPEND(_, SYSIO_INTERFACE_NAME(ireadx)), + SYSIO_INTERFACE_NAME(iread64x)) +#endif + +#if _LARGEFILE64_SOURCE +ioid_t +SYSIO_INTERFACE_NAME(ireadx)(int fd, + const struct iovec *iov, size_t iov_count, + const struct xtvec *xtv, size_t xtv_count) +{ + struct file *fil; + struct intnl_xtvec *ixtv, *ixtvent; + size_t count; + int err; + struct ioctx *ioctx; + SYSIO_INTERFACE_DISPLAY_BLOCK; + + SYSIO_INTERFACE_ENTER; + fil = _sysio_fd_find(fd); + if (!(fil && xtv_count)) + SYSIO_INTERFACE_RETURN(IOID_FAIL, -EBADF); + + ixtv = ixtvent = malloc(xtv_count * sizeof(struct intnl_xtvec)); + if (!ixtv) + SYSIO_INTERFACE_RETURN(IOID_FAIL, -ENOMEM); + + count = xtv_count; + while (count--) { + ixtvent->xtv_off = xtv->xtv_off; + ixtvent->xtv_len = xtv->xtv_len; + ixtvent++; + xtv++; + } + + err = + _sysio_iiox(IIOXOP_READ(fil->f_ino), + fil, + iov, iov_count, NULL, + ixtv, xtv_count, free_xtv, + NULL, + &ioctx); + if (err) { + free(ixtv); + SYSIO_INTERFACE_RETURN(IOID_FAIL, err); + } + SYSIO_INTERFACE_RETURN(ioctx->ioctx_id, 0); +} +#else +#undef ireadx +sysio_sym_weak_alias(PREPEND(_, SYSIO_INTERFACE_NAME(ireadx)), + SYSIO_INTERFACE_NAME(ireadx)) +#endif + +ssize_t +SYSIO_INTERFACE_NAME(readx)(int fd, + const struct iovec *iov, size_t iov_count, + const struct xtvec *xtv, size_t xtv_count) +{ + ioid_t ioid; + + if ((ioid = SYSIO_INTERFACE_NAME(ireadx)(fd, + iov, + iov_count, + xtv, + xtv_count)) == IOID_FAIL) + return -1; + return iowait(ioid); +} + +#if _LARGEFILE64_SOURCE +#undef iread64x +ssize_t +SYSIO_INTERFACE_NAME(read64x)(int fd, + const struct iovec *iov, size_t iov_count, + const struct xtvec64 *xtv, size_t xtv_count) +{ + ioid_t ioid; + + if ((ioid = SYSIO_INTERFACE_NAME(iread64x)(fd, + iov, + iov_count, + xtv, + xtv_count)) == IOID_FAIL) + return -1; + return iowait(ioid); +} +#endif + +#ifdef notdef +int +read_list(int fd, + int mem_list_count, + char *mem_offsets[], + int mem_lengths[], + int file_list_count, + int64_t file_offsets[], + int32_t file_lengths[]) +{ + SYSIO_INTERFACE_DISPLAY_BLOCK; + + SYSIO_INTERFACE_ENTER; + SYSIO_INTERFACE_RETURN(-1, -ENOSYS); +} +#endif + +ioid_t +SYSIO_INTERFACE_NAME(iwritev)(int fd, + const struct iovec *iov, + int count) +{ + struct file *fil; + struct intnl_xtvec *xtv; + struct ioctx *ioctx; + int err; + SYSIO_INTERFACE_DISPLAY_BLOCK; + + SYSIO_INTERFACE_ENTER; + fil = _sysio_fd_find(fd); + if (!fil) + SYSIO_INTERFACE_RETURN(IOID_FAIL, -EBADF); + + xtv = malloc(sizeof(struct intnl_xtvec)); + if (!xtv) + SYSIO_INTERFACE_RETURN(IOID_FAIL, -ENOMEM); + + err = + _sysio_iiov(IIOXOP_WRITE(fil->f_ino), + fil, + iov, count, NULL, + xtv, free_xtv, + &ioctx); + if (err) { + free(xtv); + SYSIO_INTERFACE_RETURN(IOID_FAIL, err); + } + SYSIO_INTERFACE_RETURN(ioctx->ioctx_id, 0); +} + +ssize_t +SYSIO_INTERFACE_NAME(writev)(int fd, const struct iovec *iov, int count) +{ + struct file *fil; + struct intnl_xtvec xtvector; + struct ioctx *ioctx; + int err; + ssize_t cc; + SYSIO_INTERFACE_DISPLAY_BLOCK; + + SYSIO_INTERFACE_ENTER; + fil = _sysio_fd_find(fd); + if (!fil) + SYSIO_INTERFACE_RETURN(-1, -EBADF); + + err = + _sysio_iiov(IIOXOP_WRITE(fil->f_ino), + fil, + iov, count, NULL, + &xtvector, NULL, + &ioctx); + if (!err && (cc = _sysio_ioctx_wait(ioctx)) < 0) + err = (int )cc; + + SYSIO_INTERFACE_RETURN(err < 0 ? -1 : cc, err); +} + +#ifdef __GLIBC__ +#undef __writev +sysio_sym_weak_alias(SYSIO_INTERFACE_NAME(writev), + PREPEND(__, SYSIO_INTERFACE_NAME(writev))) +#undef __libc_writev +sysio_sym_weak_alias(SYSIO_INTERFACE_NAME(writev), + PREPEND(__, SYSIO_INTERFACE_NAME(libc_writev))) +#endif + +ioid_t +SYSIO_INTERFACE_NAME(iwrite)(int fd, const void *buf, size_t count) +{ + struct iovec *iov; + struct file *fil; + struct intnl_xtvec *xtv; + struct ioctx *ioctx; + int err; + SYSIO_INTERFACE_DISPLAY_BLOCK; + + SYSIO_INTERFACE_ENTER; + fil = _sysio_fd_find(fd); + if (!fil) + SYSIO_INTERFACE_RETURN(IOID_FAIL, -EBADF); + + iov = malloc(sizeof(struct iovec)); + if (!iov) + SYSIO_INTERFACE_RETURN(IOID_FAIL, -ENOMEM); + + iov->iov_base = (void *)buf; + iov->iov_len = count; + xtv = malloc(sizeof(struct intnl_xtvec)); + if (!xtv) { + free(iov); + SYSIO_INTERFACE_RETURN(IOID_FAIL, -ENOMEM); + } + err = + _sysio_iiov(IIOXOP_WRITE(fil->f_ino), + fil, + iov, 1, free_iov, + xtv, free_xtv, + &ioctx); + if (err) { + free(xtv); + free(iov); + SYSIO_INTERFACE_RETURN(IOID_FAIL, err); + } + SYSIO_INTERFACE_RETURN(ioctx->ioctx_id, 0); +} + +ssize_t +SYSIO_INTERFACE_NAME(write)(int fd, const void *buf, size_t count) +{ + struct file *fil; + struct iovec iovector; + struct intnl_xtvec xtvector; + int err; + struct ioctx *ioctx; + ssize_t cc; + SYSIO_INTERFACE_DISPLAY_BLOCK; + + SYSIO_INTERFACE_ENTER; + fil = _sysio_fd_find(fd); + if (!fil) + SYSIO_INTERFACE_RETURN(-1, -EBADF); + + iovector.iov_base = (void *)buf; + iovector.iov_len = count; + err = + _sysio_iiov(IIOXOP_WRITE(fil->f_ino), + fil, + &iovector, 1, NULL, + &xtvector, NULL, + &ioctx); + if (!err && (cc = _sysio_ioctx_wait(ioctx)) < 0) + err = (int )cc; + + SYSIO_INTERFACE_RETURN(err < 0 ? -1 : cc, err); +} + +#ifdef __GLIBC__ +#undef __write +sysio_sym_weak_alias(SYSIO_INTERFACE_NAME(write), + PREPEND(__, SYSIO_INTERFACE_NAME(write))) +#undef __libc_write +sysio_sym_weak_alias(SYSIO_INTERFACE_NAME(write), + PREPEND(__, SYSIO_INTERFACE_NAME(libc_write))) +#endif + +static ioid_t +PREPEND(_, SYSIO_INTERFACE_NAME(ipwritev))(int fd, + const struct iovec *iov, + size_t count, + _SYSIO_OFF_T offset) +{ + struct file *fil; + struct intnl_xtvec *xtv; + struct ioctx *ioctx; + int err; + SYSIO_INTERFACE_DISPLAY_BLOCK; + + SYSIO_INTERFACE_ENTER; + fil = _sysio_fd_find(fd); + if (!fil) + SYSIO_INTERFACE_RETURN(IOID_FAIL, -EBADF); + + xtv = malloc(sizeof(struct intnl_xtvec)); + if (!xtv) + SYSIO_INTERFACE_RETURN(IOID_FAIL, -ENOMEM); + + err = + _sysio_ipiov(IIOXOP_WRITE(fil->f_ino), + fil, + iov, count, NULL, + offset, + xtv, free_xtv, + &ioctx); + if (err) { + free(xtv); + SYSIO_INTERFACE_RETURN(IOID_FAIL, err); + } + SYSIO_INTERFACE_RETURN(ioctx->ioctx_id, 0); +} + +#if _LARGEFILE64_SOURCE +#undef ipwrite64v +sysio_sym_weak_alias(PREPEND(_, SYSIO_INTERFACE_NAME(ipwritev)), + SYSIO_INTERFACE_NAME(ipwrite64v)) +#endif + +ioid_t +SYSIO_INTERFACE_NAME(ipwritev)(int fd, + const struct iovec *iov, + size_t count, + off_t offset) +{ + + return PREPEND(_, SYSIO_INTERFACE_NAME(ipwritev))(fd, + iov, + count, + offset); +} + +static ssize_t +PREPEND(_, SYSIO_INTERFACE_NAME(pwritev))(int fd, + const struct iovec *iov, + size_t count, + _SYSIO_OFF_T offset) +{ + struct file *fil; + struct intnl_xtvec xtvector; + struct ioctx *ioctx; + int err; + ssize_t cc; + SYSIO_INTERFACE_DISPLAY_BLOCK; + + SYSIO_INTERFACE_ENTER; + fil = _sysio_fd_find(fd); + if (!fil) + SYSIO_INTERFACE_RETURN(-1, -EBADF); + + err = + _sysio_ipiov(IIOXOP_WRITE(fil->f_ino), + fil, + iov, count, NULL, + offset, + &xtvector, NULL, + &ioctx); + if (!err && (cc = _sysio_ioctx_wait(ioctx)) < 0) + err = (int )cc; + + SYSIO_INTERFACE_RETURN(err ? -1 : cc, err); +} + +#if _LARGEFILE64_SOURCE +#undef pwrite64v +sysio_sym_weak_alias(PREPEND(_, SYSIO_INTERFACE_NAME(pwritev)), + SYSIO_INTERFACE_NAME(pwrite64v)) +#endif + +ssize_t +SYSIO_INTERFACE_NAME(pwritev)(int fd, + const struct iovec *iov, + size_t count, + off_t offset) +{ + + return PREPEND(_, SYSIO_INTERFACE_NAME(pwritev))(fd, + iov, + count, + offset); +} + +static ioid_t +PREPEND(_, SYSIO_INTERFACE_NAME(ipwrite))(int fd, + const void *buf, + size_t count, + _SYSIO_OFF_T offset) +{ + struct file *fil; + struct intnl_xtvec *xtv; + struct iovec *iov; + struct ioctx *ioctx; + int err; + SYSIO_INTERFACE_DISPLAY_BLOCK; + + SYSIO_INTERFACE_ENTER; + fil = _sysio_fd_find(fd); + if (!fil) + SYSIO_INTERFACE_RETURN(IOID_FAIL, -EBADF); + + xtv = malloc(sizeof(struct intnl_xtvec)); + iov = malloc(sizeof(struct iovec)); + if (!(xtv && iov)) { + err = -errno; + goto error; + } + xtv->xtv_off = offset; + iov->iov_base = (void *)buf; + xtv->xtv_len = iov->iov_len = count; + err = + _sysio_ipiov(IIOXOP_WRITE(fil->f_ino), + fil, + iov, 1, free_iov, + offset, + xtv, free_xtv, + &ioctx); +error: + if (err) { + if (iov) + free(iov); + if (xtv) + free(xtv); + SYSIO_INTERFACE_RETURN(IOID_FAIL, err); + } + SYSIO_INTERFACE_RETURN(ioctx->ioctx_id, 0); +} + +#if _LARGEFILE64_SOURCE +#undef ipwrite64 +sysio_sym_weak_alias(PREPEND(_, SYSIO_INTERFACE_NAME(ipwrite)), + SYSIO_INTERFACE_NAME(ipwrite64)) +#endif + +ioid_t +SYSIO_INTERFACE_NAME(ipwrite)(int fd, + const void *buf, + size_t count, + off_t offset) +{ + + return PREPEND(_, SYSIO_INTERFACE_NAME(ipwrite))(fd, + buf, + count, + offset); +} + +ssize_t +PREPEND(_, SYSIO_INTERFACE_NAME(pwrite))(int fd, + const void *buf, + size_t count, + _SYSIO_OFF_T offset) +{ + struct file *fil; + struct intnl_xtvec xtvec; + struct iovec iovec; + struct ioctx *ioctx; + int err; + ssize_t cc; + SYSIO_INTERFACE_DISPLAY_BLOCK; + + SYSIO_INTERFACE_ENTER; + fil = _sysio_fd_find(fd); + if (!fil) + SYSIO_INTERFACE_RETURN(-1, -EBADF); + + xtvec.xtv_off = offset; + iovec.iov_base = (void *)buf; + xtvec.xtv_len = iovec.iov_len = count; + err = + _sysio_ipiov(IIOXOP_WRITE(fil->f_ino), + fil, + &iovec, 1, NULL, + offset, + &xtvec, NULL, + &ioctx); + if (!err && (cc = _sysio_ioctx_wait(ioctx)) < 0) + err = (int )cc; + + SYSIO_INTERFACE_RETURN(err ? -1 : cc, err); +} + +#if _LARGEFILE64_SOURCE +#undef pwrite64 +sysio_sym_weak_alias(PREPEND(_, SYSIO_INTERFACE_NAME(pwrite)), + SYSIO_INTERFACE_NAME(pwrite64)) +#ifdef __GLIBC +#undef __pwrite64 +sysio_sym_weak_alias(PREPEND(_, SYSIO_INTERFACE_NAME(pwrite)), + PREPEND(__, SYSIO_INTERFACE_NAME(pwrite64))) +#undef __libc_pwrite64 +sysio_sym_weak_alias(PREPEND(_, SYSIO_INTERFACE_NAME(pwrite)), + PREPEND(__, SYSIO_INTERFACE_NAME(libc_pwrite64))) +#endif +#endif + +ssize_t +SYSIO_INTERFACE_NAME(pwrite)(int fd, + const void *buf, + size_t count, + off_t offset) +{ + + return PREPEND(_, SYSIO_INTERFACE_NAME(pwrite))(fd, + buf, + count, + offset); +} + +#ifdef __GLIBC +#undef __libc_pwrite +sysio_sym_weak_alias(SYSIO_INTERFACE_NAME(pwrite), __libc_pwrite) + PREPEND(__, SYSIO_INTERFACE_NAME(libc_pwrite))) +#endif + +static ioid_t +PREPEND(_, SYSIO_INTERFACE_NAME(iwritex))(int fd, + const struct iovec *iov, + size_t iov_count, + const struct intnl_xtvec *xtv, + size_t xtv_count) +{ + struct file *fil; + int err; + struct ioctx *ioctx; + SYSIO_INTERFACE_DISPLAY_BLOCK; + + SYSIO_INTERFACE_ENTER; + fil = _sysio_fd_find(fd); + if (!(fil && xtv_count)) + SYSIO_INTERFACE_RETURN(IOID_FAIL, -EBADF); + + err = + _sysio_iiox(IIOXOP_WRITE(fil->f_ino), + fil, + iov, iov_count, NULL, + xtv, xtv_count, NULL, + NULL, + &ioctx); + + SYSIO_INTERFACE_RETURN(err ? IOID_FAIL : ioctx->ioctx_id, err); +} + +#if _LARGEFILE64_SOURCE +#undef iwrite64x +sysio_sym_weak_alias(PREPEND(_, SYSIO_INTERFACE_NAME(iwritex)), + SYSIO_INTERFACE_NAME(iwrite64x)) +#endif + +#if _LARGEFILE64_SOURCE +ioid_t +SYSIO_INTERFACE_NAME(iwritex)(int fd, + const struct iovec *iov, size_t iov_count, + const struct xtvec *xtv, size_t xtv_count) +{ + struct file *fil; + struct intnl_xtvec *ixtv, *ixtvent; + size_t count; + int err; + struct ioctx *ioctx; + SYSIO_INTERFACE_DISPLAY_BLOCK; + + SYSIO_INTERFACE_ENTER; + fil = _sysio_fd_find(fd); + if (!(fil && xtv_count)) + SYSIO_INTERFACE_RETURN(IOID_FAIL, -EBADF); + + ixtv = ixtvent = malloc(xtv_count * sizeof(struct intnl_xtvec)); + if (!ixtv) + SYSIO_INTERFACE_RETURN(IOID_FAIL, -ENOMEM); + + count = xtv_count; + while (count--) { + ixtvent->xtv_off = xtv->xtv_off; + ixtvent->xtv_len = xtv->xtv_len; + ixtvent++; + xtv++; + } + + err = + _sysio_iiox(IIOXOP_WRITE(fil->f_ino), + fil, + iov, iov_count, NULL, + ixtv, xtv_count, free_xtv, + NULL, + &ioctx); + if (err) { + free(ixtv); + SYSIO_INTERFACE_RETURN(IOID_FAIL, err); + } + SYSIO_INTERFACE_RETURN(ioctx->ioctx_id, 0); +} +#else +#undef iwritex +sysio_sym_weak_alias(PREPEND(_, SYSIO_INTERFACE_NAME(iwritex)), + SYSIO_INTERFACE_NAME(iwritex)) +#endif + +#undef writex +ssize_t +SYSIO_INTERFACE_NAME(writex)(int fd, + const struct iovec *iov, size_t iov_count, + const struct xtvec *xtv, size_t xtv_count) +{ + ioid_t ioid; + + if ((ioid = + SYSIO_INTERFACE_NAME(iwritex)(fd, + iov, + iov_count, + xtv, + xtv_count)) == IOID_FAIL) + return -1; + return iowait(ioid); +} + +#if _LARGEFILE64_SOURCE +#undef write64x +ssize_t +SYSIO_INTERFACE_NAME(write64x)(int fd, + const struct iovec *iov, size_t iov_count, + const struct xtvec64 *xtv, size_t xtv_count) +{ + ioid_t ioid; + + if ((ioid = SYSIO_INTERFACE_NAME(iwrite64x)(fd, + iov, + iov_count, + xtv, + xtv_count)) == IOID_FAIL) + return -1; + return iowait(ioid); +} +#endif + +#ifdef notdef +int +write_list(int fd, + int mem_list_count, + char *mem_offsets[], + int mem_lengths[], + int file_list_count, + int64_t file_offsets[], + int32_t file_lengths[]) +{ + SYSIO_INTERFACE_DISPLAY_BLOCK; + + SYSIO_INTERFACE_ENTER; + SYSIO_INTERFACE_RETURN(-1, -ENOSYS); +} +#endif diff --git a/libsysio/src/stat.c b/libsysio/src/stat.c new file mode 100644 index 0000000..4fec1f1 --- /dev/null +++ b/libsysio/src/stat.c @@ -0,0 +1,298 @@ +/* + * This Cplant(TM) source code is the property of Sandia National + * Laboratories. + * + * This Cplant(TM) source code is copyrighted by Sandia National + * Laboratories. + * + * The redistribution of this Cplant(TM) source code is subject to the + * terms of the GNU Lesser General Public License + * (see cit/LGPL or http://www.gnu.org/licenses/lgpl.html) + * + * Cplant(TM) Copyright 1998-2003 Sandia Corporation. + * Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive + * license for use of this work by or on behalf of the US Government. + * Export of this program may require a license from the United States + * Government. + */ + +/* + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Questions or comments about this library should be sent to: + * + * Lee Ward + * Sandia National Laboratories, New Mexico + * P.O. Box 5800 + * Albuquerque, NM 87185-1110 + * + * lee@sandia.gov + */ + +#include +#include +#include +#include +#include +#include + +#include "sysio.h" +#include "inode.h" +#include "file.h" + +#include "sysio-symbols.h" + +#ifndef REDSTORM +#undef fstat +#undef stat +#undef lstat +#endif + +#undef __fxstat +#undef __xstat +#undef __lxstat + +#if !defined(_STAT_VER) +#define _STAT_VER 0 +#endif + +#if _LARGEFILE64_SOURCE +static void +convstat(struct stat64 *st64_buf, struct stat *st_buf) +{ + + st_buf->st_dev = st64_buf->st_dev; + st_buf->st_ino = st64_buf->st_ino; + st_buf->st_mode = st64_buf->st_mode; + st_buf->st_nlink = st64_buf->st_nlink; + st_buf->st_uid = st64_buf->st_uid; + st_buf->st_gid = st64_buf->st_gid; + st_buf->st_rdev = st64_buf->st_rdev; + st_buf->st_size = st64_buf->st_size; + st_buf->st_blksize = st64_buf->st_blksize; + st_buf->st_blocks = st64_buf->st_blocks; + st_buf->st_atime = st64_buf->st_atime; + st_buf->st_mtime = st64_buf->st_mtime; + st_buf->st_ctime = st64_buf->st_ctime; +} +#endif + +int +PREPEND(__, SYSIO_INTERFACE_NAME(fxstat))(int __ver, + int __fildes, + struct stat *__stat_buf) +{ + struct file *fil; + int err; + struct intnl_stat *buf; +#if _LARGEFILE64_SOURCE + struct stat64 st64; +#endif + SYSIO_INTERFACE_DISPLAY_BLOCK; + + SYSIO_INTERFACE_ENTER; + if (__ver != _STAT_VER) { + err = -ENOSYS; + goto out; + } + + err = 0; + fil = _sysio_fd_find(__fildes); + if (!fil) { + err = -EBADF; + goto out; + } +#if _LARGEFILE64_SOURCE + buf = &st64; +#else + buf = __stat_buf; +#endif + err = + fil->f_ino->i_ops.inop_getattr(NULL, fil->f_ino, buf); +#if _LARGEFILE64_SOURCE + if (!err) + convstat(buf, __stat_buf); +#endif +out: + SYSIO_INTERFACE_RETURN(err ? -1 : 0, err); +} + +#ifdef REDSTORM +#undef _fxstat +sysio_sym_weak_alias(PREPEND(__, SYSIO_INTERFACE_NAME(fxstat)), + PREPEND(_, SYSIO_INTERFACE_NAME(fxstat))) +#endif + +#ifndef REDSTORM +static int +PREPEND(__, SYSIO_INTERFACE_NAME(fstat))(int fd, struct stat *buf) +{ + + return PREPEND(__, SYSIO_INTERFACE_NAME(fxstat))(_STAT_VER, + fd, + buf); +} + +sysio_sym_weak_alias(PREPEND(__, SYSIO_INTERFACE_NAME(fstat)), + SYSIO_INTERFACE_NAME(fstat)) + +#ifdef BSD +#undef _fstat +sysio_sym_weak_alias(PREPEND(__, SYSIO_INTERFACE_NAME(fstat)), + PREPEND(_, SYSIO_INTERFACE_NAME(fstat))) +#endif +#endif + +int +PREPEND(__, SYSIO_INTERFACE_NAME(xstat))(int __ver, + const char *__filename, + struct stat *__stat_buf) +{ + struct intent intent; + int err; + struct pnode *pno; + struct inode *ino; + struct intnl_stat *buf; +#if _LARGEFILE64_SOURCE + struct stat64 st64; +#endif + SYSIO_INTERFACE_DISPLAY_BLOCK; + + SYSIO_INTERFACE_ENTER; + if (__ver != _STAT_VER) { + err = -ENOSYS; + goto out; + } + + INTENT_INIT(&intent, INT_GETATTR, NULL, NULL); + err = _sysio_namei(_sysio_cwd, __filename, 0, &intent, &pno); + if (err) + goto out; + ino = pno->p_base->pb_ino; +#if _LARGEFILE64_SOURCE + buf = &st64; +#else + buf = __stat_buf; +#endif + err = + ino->i_ops.inop_getattr(pno, + pno->p_base->pb_ino, + buf); + + P_RELE(pno); +#if _LARGEFILE64_SOURCE + if (!err) + convstat(buf, __stat_buf); +#endif +out: + SYSIO_INTERFACE_RETURN(err ? -1 : 0, err); +} + +#ifdef REDSTORM +#undef _xstat +sysio_sym_weak_alias(PREPEND(__, SYSIO_INTERFACE_NAME(xstat)), + PREPEND(_, SYSIO_INTERFACE_NAME(xstat))) +#endif + +#ifndef REDSTORM +static int +PREPEND(__, SYSIO_INTERFACE_NAME(stat))(const char *filename, + struct stat *buf) +{ + + return PREPEND(__, SYSIO_INTERFACE_NAME(xstat))(_STAT_VER, + filename, + buf); +} + +sysio_sym_weak_alias(PREPEND(__, SYSIO_INTERFACE_NAME(stat)), + SYSIO_INTERFACE_NAME(stat)) + +#ifdef BSD +#undef _stat +sysio_sym_weak_alias(PREPEND(__, SYSIO_INTERFACE_NAME(stat)), + PREPEND(_, SYSIO_INTERFACE_NAME(stat))) +#endif +#endif + +int +PREPEND(__, SYSIO_INTERFACE_NAME(lxstat))(int __ver, + const char *__filename, + struct stat *__stat_buf) +{ + struct intent intent; + int err; + struct pnode *pno; + struct inode *ino; + struct intnl_stat *buf; +#if _LARGEFILE64_SOURCE + struct stat64 st64; +#endif + SYSIO_INTERFACE_DISPLAY_BLOCK; + + SYSIO_INTERFACE_ENTER; + if (__ver != _STAT_VER) { + err = -ENOSYS; + goto out; + } + + INTENT_INIT(&intent, INT_GETATTR, NULL, NULL); + err = _sysio_namei(_sysio_cwd, __filename, ND_NOFOLLOW, &intent, &pno); + if (err) + goto out; +#if _LARGEFILE64_SOURCE + buf = &st64; +#else + buf = __stat_buf; +#endif + ino = pno->p_base->pb_ino; + err = + ino->i_ops.inop_getattr(pno, + pno->p_base->pb_ino, + buf); + + P_RELE(pno); +#if _LARGEFILE64_SOURCE + if (!err) + convstat(buf, __stat_buf); +#endif +out: + SYSIO_INTERFACE_RETURN(err ? -1 : 0, err); +} + +#ifdef REDSTORM +#undef _lxstat +sysio_sym_weak_alias(PREPEND(__, SYSIO_INTERFACE_NAME(lxstat)), + PREPEND(_, SYSIO_INTERFACE_NAME(lxstat))) +#endif + +#ifndef REDSTORM +static int +PREPEND(__, SYSIO_INTERFACE_NAME(lstat))(const char *filename, struct stat *buf) +{ + return PREPEND(__, SYSIO_INTERFACE_NAME(lxstat))(_STAT_VER, + filename, + buf); +} + +sysio_sym_weak_alias(PREPEND(__, SYSIO_INTERFACE_NAME(lstat)), + SYSIO_INTERFACE_NAME(lstat)) + +#ifdef BSD +#undef _lstat +sysio_sym_weak_alias(PREPEND(__, SYSIO_INTERFACE_NAME(lstat)), + PREPEND(_, SYSIO_INTERFACE_NAME(lstat))) +#endif +#endif diff --git a/libsysio/src/stat64.c b/libsysio/src/stat64.c new file mode 100644 index 0000000..377e2dc --- /dev/null +++ b/libsysio/src/stat64.c @@ -0,0 +1,181 @@ +/* + * This Cplant(TM) source code is the property of Sandia National + * Laboratories. + * + * This Cplant(TM) source code is copyrighted by Sandia National + * Laboratories. + * + * The redistribution of this Cplant(TM) source code is subject to the + * terms of the GNU Lesser General Public License + * (see cit/LGPL or http://www.gnu.org/licenses/lgpl.html) + * + * Cplant(TM) Copyright 1998-2003 Sandia Corporation. + * Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive + * license for use of this work by or on behalf of the US Government. + * Export of this program may require a license from the United States + * Government. + */ + +/* + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Questions or comments about this library should be sent to: + * + * Lee Ward + * Sandia National Laboratories, New Mexico + * P.O. Box 5800 + * Albuquerque, NM 87185-1110 + * + * lee@sandia.gov + */ + +#ifdef _LARGEFILE64_SOURCE + +#include +#include +#include +#include +#include +#include + +#include "sysio.h" +#include "inode.h" +#include "file.h" + +#ifndef REDSTORM +#undef fstat64 +#undef stat64 +#undef lstat64 +#endif + +#undef __fxstat64 +#undef __xstat64 +#undef __lxstat64 + +int +PREPEND(__, SYSIO_INTERFACE_NAME(fxstat64))(int __ver, + int __fildes, + struct stat64 *__stat_buf) +{ + struct file *fil; + int err; + SYSIO_INTERFACE_DISPLAY_BLOCK; + + SYSIO_INTERFACE_ENTER; + if (__ver != _STAT_VER) { + err = -ENOSYS; + goto out; + } + + err = 0; + fil = _sysio_fd_find(__fildes); + if (!fil) { + err = -EBADF; + goto out; + } + err = fil->f_ino->i_ops.inop_getattr(NULL, fil->f_ino, __stat_buf); +out: + SYSIO_INTERFACE_RETURN(err ? -1 : 0, err); +} + +#ifndef REDSTORM +int +SYSIO_INTERFACE_NAME(fstat64)(int fd, struct stat64 *buf) +{ + + return PREPEND(__, SYSIO_INTERFACE_NAME(fxstat64))(_STAT_VER, fd, buf); +} +#endif + +int +PREPEND(__, SYSIO_INTERFACE_NAME(xstat64))(int __ver, + const char *__filename, + struct stat64 *__stat_buf) +{ + struct intent intent; + int err; + struct pnode *pno; + SYSIO_INTERFACE_DISPLAY_BLOCK; + + SYSIO_INTERFACE_ENTER; + if (__ver != _STAT_VER) { + err = -ENOSYS; + goto out; + } + + INTENT_INIT(&intent, INT_GETATTR, NULL, NULL); + err = _sysio_namei(_sysio_cwd, __filename, 0, &intent, &pno); + if (err) + goto out; + err = + pno->p_base->pb_ino->i_ops.inop_getattr(pno, + pno->p_base->pb_ino, + __stat_buf); + P_RELE(pno); +out: + SYSIO_INTERFACE_RETURN(err ? -1 : 0, err); +} + +#ifndef REDSTORM +int +SYSIO_INTERFACE_NAME(stat64)(const char *filename, struct stat64 *buf) +{ + + return PREPEND(__, SYSIO_INTERFACE_NAME(xstat64))(_STAT_VER, + filename, + buf); +} +#endif + +int +PREPEND(__, SYSIO_INTERFACE_NAME(lxstat64))(int __ver, + const char *__filename, + struct stat64 *__stat_buf) +{ + struct intent intent; + int err; + struct pnode *pno; + SYSIO_INTERFACE_DISPLAY_BLOCK; + + SYSIO_INTERFACE_ENTER; + if (__ver != _STAT_VER) { + err = -ENOSYS; + goto out; + } + + INTENT_INIT(&intent, INT_GETATTR, NULL, NULL); + err = _sysio_namei(_sysio_cwd, __filename, ND_NOFOLLOW, &intent, &pno); + if (err) + goto out; + err = + pno->p_base->pb_ino->i_ops.inop_getattr(pno, + pno->p_base->pb_ino, + __stat_buf); + P_RELE(pno); +out: + SYSIO_INTERFACE_RETURN(err ? -1 : 0, err); +} + +#ifndef REDSTORM +int +SYSIO_INTERFACE_NAME(lstat64)(const char *filename, struct stat64 *buf) +{ + + return PREPEND(__, SYSIO_INTERFACE_NAME(lxstat64))(_STAT_VER, + filename, + buf); +} +#endif +#endif /* !_LARGEFILE64_SOURCE */ diff --git a/libsysio/src/statvfs.c b/libsysio/src/statvfs.c new file mode 100644 index 0000000..5f07387 --- /dev/null +++ b/libsysio/src/statvfs.c @@ -0,0 +1,155 @@ +/* + * This Cplant(TM) source code is the property of Sandia National + * Laboratories. + * + * This Cplant(TM) source code is copyrighted by Sandia National + * Laboratories. + * + * The redistribution of this Cplant(TM) source code is subject to the + * terms of the GNU Lesser General Public License + * (see cit/LGPL or http://www.gnu.org/licenses/lgpl.html) + * + * Cplant(TM) Copyright 1998-2003 Sandia Corporation. + * Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive + * license for use of this work by or on behalf of the US Government. + * Export of this program may require a license from the United States + * Government. + */ + +/* + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Questions or comments about this library should be sent to: + * + * Lee Ward + * Sandia National Laboratories, New Mexico + * P.O. Box 5800 + * Albuquerque, NM 87185-1110 + * + * lee@sandia.gov + */ + +#ifndef BSD + +#include +#include +#include +#include +#include +#include + +#include "sysio.h" +#include "inode.h" +#include "file.h" +#include "sysio-symbols.h" + +#undef statvfs +#undef fstatvfs + +#ifndef INTNL_STATVFS_IS_NATURAL +static void +convstatvfs(struct statvfs *stvfsbuf, struct intnl_statvfs *istvfsbuf) +{ + stvfsbuf->f_bsize = istvfsbuf->f_bsize; + stvfsbuf->f_frsize = istvfsbuf->f_frsize; + stvfsbuf->f_blocks = (unsigned long )istvfsbuf->f_blocks; + stvfsbuf->f_bfree = (unsigned long )istvfsbuf->f_bfree; + stvfsbuf->f_bavail = (unsigned long )istvfsbuf->f_bavail; + stvfsbuf->f_files = (unsigned long )istvfsbuf->f_files; + stvfsbuf->f_ffree = (unsigned long )istvfsbuf->f_ffree; + stvfsbuf->f_favail = (unsigned long )istvfsbuf->f_favail; + stvfsbuf->f_fsid = istvfsbuf->f_fsid; + stvfsbuf->f_flag = istvfsbuf->f_flag; + stvfsbuf->f_namemax = istvfsbuf->f_namemax; +} +#endif + +int +SYSIO_INTERFACE_NAME(statvfs)(const char *path, struct statvfs *buf) +{ + int err; + struct pnode *pno; +#ifdef INTNL_STATVFS_IS_NATURAL +#define _call_buf buf +#else + struct intnl_statvfs _call_buffer; + struct intnl_statvfs *_call_buf = &_call_buffer; +#endif + SYSIO_INTERFACE_DISPLAY_BLOCK; + + SYSIO_INTERFACE_ENTER; + err = _sysio_namei(_sysio_cwd, path, 0, NULL, &pno); + if (err) + goto out; + + err = pno->p_base->pb_ino->i_ops.inop_statvfs(pno, NULL, _call_buf); + P_RELE(pno); + if (err) + goto err; +#ifndef INTNL_STATVFS_IS_NATURAL + convstatvfs(buf, _call_buf); +#endif + goto out; +err: +out: + SYSIO_INTERFACE_RETURN(err ? -1 : 0, err); +} + +#ifdef REDSTORM +#undef __statvfs +sysio_sym_weak_alias(SYSIO_INTERFACE_NAME(statvfs), + PREPEND(__, SYSIO_INTERFACE_NAME(statvfs))) +#endif + +int +SYSIO_INTERFACE_NAME(fstatvfs)(int fd, struct statvfs *buf) +{ + int err; + struct file *filp; +#ifdef INTNL_STATVFS_IS_NATURAL +#define _call_buf buf +#else + struct intnl_statvfs _call_buffer; + struct intnl_statvfs *_call_buf = &_call_buffer; +#endif + SYSIO_INTERFACE_DISPLAY_BLOCK; + + SYSIO_INTERFACE_ENTER; + err = 0; + filp = _sysio_fd_find(fd); + if (!filp) { + err = -EBADF; + goto out; + } + + err = filp->f_ino->i_ops.inop_statvfs(NULL, filp->f_ino, _call_buf); + if (err) + goto err; +#ifndef INTNL_STATVFS_IS_NATURAL + convstatvfs(buf, _call_buf); +#endif + goto out; +err: +out: + SYSIO_INTERFACE_RETURN(err ? -1 : 0, err); +} + +#ifdef REDSTORM +#undef __fstatvfs +sysio_sym_weak_alias(SYSIO_INTERFACE_NAME(fstatvfs), + PREPEND(__, SYSIO_INTERFACE_NAME(fstatvfs))) +#endif + +#endif /* ifndef BSD */ diff --git a/libsysio/src/statvfs64.c b/libsysio/src/statvfs64.c new file mode 100644 index 0000000..c89c969 --- /dev/null +++ b/libsysio/src/statvfs64.c @@ -0,0 +1,107 @@ +/* + * This Cplant(TM) source code is the property of Sandia National + * Laboratories. + * + * This Cplant(TM) source code is copyrighted by Sandia National + * Laboratories. + * + * The redistribution of this Cplant(TM) source code is subject to the + * terms of the GNU Lesser General Public License + * (see cit/LGPL or http://www.gnu.org/licenses/lgpl.html) + * + * Cplant(TM) Copyright 1998-2003 Sandia Corporation. + * Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive + * license for use of this work by or on behalf of the US Government. + * Export of this program may require a license from the United States + * Government. + */ + +/* + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Questions or comments about this library should be sent to: + * + * Lee Ward + * Sandia National Laboratories, New Mexico + * P.O. Box 5800 + * Albuquerque, NM 87185-1110 + * + * lee@sandia.gov + */ + +#ifndef BSD +#include +#include +#include +#include +#include +#include + +#include "sysio.h" +#include "inode.h" +#include "file.h" +#include "sysio-symbols.h" + +int +SYSIO_INTERFACE_NAME(statvfs64)(const char *path, struct statvfs64 *buf) +{ + int err; + struct pnode *pno; + SYSIO_INTERFACE_DISPLAY_BLOCK; + + SYSIO_INTERFACE_ENTER; + err = _sysio_namei(_sysio_cwd, path, 0, NULL, &pno); + if (err) + goto out; + + err = pno->p_base->pb_ino->i_ops.inop_statvfs(pno, NULL, buf); + P_RELE(pno); +out: + SYSIO_INTERFACE_RETURN(err ? -1 : 0, err); +} + +#ifdef REDSTORM +#undef __statvfs64 +sysio_sym_weak_alias(SYSIO_INTERFACE_NAME(statvfs64), + PREPEND(__, SYSIO_INTERFACE_NAME(statvfs64))) +#endif + +int +SYSIO_INTERFACE_NAME(fstatvfs64)(int fd, struct statvfs64 *buf) +{ + int err; + struct file *filp; + SYSIO_INTERFACE_DISPLAY_BLOCK; + + SYSIO_INTERFACE_ENTER; + err = 0; + filp = _sysio_fd_find(fd); + if (!filp) { + err = -EBADF; + goto out; + } + + err = filp->f_ino->i_ops.inop_statvfs(NULL, filp->f_ino, buf); +out: + SYSIO_INTERFACE_RETURN(err ? -1 : 0, err); +} + +#ifdef REDSTORM +#undef __fstatvfs64 +sysio_sym_weak_alias(SYSIO_INTERFACE_NAME(fstatvfs64), + PREPEND(__, SYSIO_INTERFACE_NAME(fstatvfs64))) +#endif + +#endif /* ifndef BSD */ diff --git a/libsysio/src/stdlib.c b/libsysio/src/stdlib.c new file mode 100644 index 0000000..7446f35 --- /dev/null +++ b/libsysio/src/stdlib.c @@ -0,0 +1,313 @@ +/* + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +/* + * stdlib.c + * + * The only purpose of this file is help liblustre adaptive to more + * applications, and specifically for running on Linux. The ideal + * final solution would be remove this completely and only rely on + * system call interception. Unfortunately we failed to find that + * way at the moment. + * + * Initially we try the simplest implementation here, just get a confidence + * it could work. + * + */ +#if !(defined(BSD) || defined(REDSTORM)) + +#include +#include +#include +#include + +#include + +#include "sysio-symbols.h" + +#if !defined(__USE_LARGEFILE64) +#error "__LARGEFILE64_SOURCE must be defined" +#endif + + +/*********************************************************** + * dir series functions * + ***********************************************************/ + +#undef BUFSIZE +#define BUFSIZE 4096 + +struct __dirstream { + int fd; + loff_t base; + loff_t filepos; /* current pos in dir file stream */ + struct dirent *curent; /* current dirent pointer */ + struct dirent64 *curent64; /* current dirent64 pointer */ + struct dirent *retent; /* ent returned to caller */ + struct dirent64 *retent64; /* ent64 returned to caller */ + unsigned int effective; /* effective data size in buffer */ + char buf[BUFSIZE]; +}; + +DIR* opendir(const char *name) +{ + DIR *dir; + + dir = (DIR *) malloc(sizeof(*dir)); + if (!dir) { + errno = ENOMEM; + return NULL; + } + +#if __USE_LARGEFILE64 + dir->fd = open64(name, O_RDONLY); +#else + dir->fd = open(name, O_RDONLY); +#endif + if (dir->fd < 0) + goto err_out; + + dir->base = 0; + dir->filepos = 0; + dir->curent = (struct dirent *) dir->buf; + dir->curent64 = (struct dirent64 *) dir->buf; + dir->retent = NULL; + dir->retent64 = NULL; + dir->effective = 0; + + return dir; +err_out: + free(dir); + return NULL; +} + +sysio_sym_weak_alias(opendir, __opendir); + +struct dirent64 *readdir64(DIR *dir) +{ + int rc, reclen; + + /* need to read new data? */ + if ((char*)dir->curent64 - dir->buf >= dir->effective) { + rc = getdirentries64(dir->fd, dir->buf, BUFSIZE, &dir->base); + /* error or end-of-file */ + if (rc <= 0) + return NULL; + + dir->curent64 = (struct dirent64 *) dir->buf; + dir->effective = rc; + } + + dir->retent64 = dir->curent64; + dir->curent64 = (struct dirent64*) ((char *)(dir->curent64) + + dir->curent64->d_reclen); +#ifdef _DIRENT_HAVE_D_OFF + dir->filepos = dir->curent64->d_off; +#else + dir->filepos += dir->curent64->d_reclen; +#endif + return dir->retent64; +} + +sysio_sym_weak_alias(readdir64, __readdir64); + +/* XXX probably the following assumption is not true */ +#if __WORDSIZE == 64 +#define NATURAL_READDIR64 +#else +#undef NATURAL_READDIR64 +#endif + +#ifndef NATURAL_READDIR64 + +struct dirent *readdir(DIR *dir) +{ + int rc, reclen; + + /* need to read new data? */ + if ((char*)dir->curent - dir->buf >= dir->effective) { + rc = getdirentries(dir->fd, dir->buf, BUFSIZE, (off_t*) &dir->base); + /* error or end-of-file */ + if (rc <= 0) + return NULL; + + dir->curent = (struct dirent *) dir->buf; + dir->effective = rc; + } + + dir->retent = dir->curent; + dir->curent = (struct dirent*) ((char *)(dir->curent) + + dir->curent->d_reclen); +#ifdef _DIRENT_HAVE_D_OFF + dir->filepos = dir->curent->d_off; +#else + dir->filepos += dir->curent->d_reclen; +#endif + return dir->retent; +} +sysio_sym_weak_alias(readdir, __readdir); + +#else /* NATURAL_READDIR64 */ + +struct dirent *readdir(DIR *dir) { + return (struct dirent *) readdir64(dir); +} +sysio_sym_weak_alias(readdir, __readdir); + +#endif /* NATURAL_READDIR64 */ + +int closedir(DIR *dir) +{ + int rc; + + rc = close(dir->fd); + + free(dir); + return rc; +} + +sysio_sym_weak_alias(closedir, __closedir); + +int dirfd(DIR *dir) +{ + return dir->fd; +} + +off_t telldir(DIR *dir) +{ + return (dir->filepos); +} + +void seekdir(DIR *dir, off_t offset) +{ + dir->filepos = offset; + + dir->base = offset; + dir->curent64 = (struct dirent64 *) dir->buf; + dir->retent64 = NULL; + dir->effective = 0; + dir->curent = (struct dirent *) dir->buf; + dir->retent = NULL; +} + +void rewinddir(DIR *dir) +{ + dir->base = 0; + dir->filepos = 0; + dir->curent64 = (struct dirent64 *) dir->buf; + dir->retent64 = NULL; + dir->curent = (struct dirent *) dir->buf; + dir->retent = NULL; + dir->effective = 0; +} + +int scandir(const char *dir, struct dirent ***namelist, + int(*select)(const struct dirent *), + int(*compar)(const void *, const void *)) +{ + errno = ENOSYS; + return -1; +} + +int scandir64(const char *dir, struct dirent64 ***namelist, + int(*select)(const struct dirent64 *), + int(*compar)(const void *, const void *)) +{ + errno = ENOSYS; + return -1; +} + +/*********************************************************** + * FIXME workaround for linux only * + ***********************************************************/ + +#define LINUX +#if defined(LINUX) +ssize_t getxattr(char *path, char *name, void *value, size_t size) +{ + errno = ENOSYS; + return -1; +} + +ssize_t lgetxattr(char *path, char *name, void *value, size_t size) +{ + errno = ENOSYS; + return -1; +} + +ssize_t fgetxattr(int fd, char *name, void *value, size_t size) +{ + errno = ENOSYS; + return -1; +} + +long setxattr(char *path, char *name, void *value, size_t size, int flags) +{ + errno = ENOSYS; + return -1; +} + +long lsetxattr(char *path, char *name, void *value, size_t size, int flags) +{ + errno = ENOSYS; + return -1; +} + +long fsetxattr(int fd, char *name, void *value, size_t size, int flags) +{ + errno = ENOSYS; + return -1; +} + +long listxattr(char *path, char *list, size_t size) +{ + errno = ENOSYS; + return -1; +} + +long llistxattr(char *path, char *list, size_t size) +{ + errno = ENOSYS; + return -1; +} + +long flistxattr(int fd, char *list, size_t size) +{ + errno = ENOSYS; + return -1; +} + +long removexattr(char *path, char *name) +{ + errno = ENOSYS; + return -1; +} + +long lremovexattr(char *path, char *name) +{ + errno = ENOSYS; + return -1; +} + +long fremovexattr(int fd, char *name) +{ + errno = ENOSYS; + return -1; +} +#endif + +#endif diff --git a/libsysio/src/symlink.c b/libsysio/src/symlink.c new file mode 100644 index 0000000..1142432 --- /dev/null +++ b/libsysio/src/symlink.c @@ -0,0 +1,90 @@ +/* + * This Cplant(TM) source code is the property of Sandia National + * Laboratories. + * + * This Cplant(TM) source code is copyrighted by Sandia National + * Laboratories. + * + * The redistribution of this Cplant(TM) source code is subject to the + * terms of the GNU Lesser General Public License + * (see cit/LGPL or http://www.gnu.org/licenses/lgpl.html) + * + * Cplant(TM) Copyright 1998-2003 Sandia Corporation. + * Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive + * license for use of this work by or on behalf of the US Government. + * Export of this program may require a license from the United States + * Government. + */ + +/* + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Questions or comments about this library should be sent to: + * + * Lee Ward + * Sandia National Laboratories, New Mexico + * P.O. Box 5800 + * Albuquerque, NM 87185-1110 + * + * lee@sandia.gov + */ + +#include +#include +#include +#include +#include + +#include "sysio.h" +#include "inode.h" +#include "fs.h" +#include "mount.h" +#include "sysio-symbols.h" + +int +SYSIO_INTERFACE_NAME(symlink)(const char *oldpath, const char *newpath) +{ + int err; + struct intent intent; + struct pnode *pno; + SYSIO_INTERFACE_DISPLAY_BLOCK; + + SYSIO_INTERFACE_ENTER; + INTENT_INIT(&intent, INT_CREAT, NULL, NULL); + err = _sysio_namei(_sysio_cwd, newpath, ND_NEGOK, &intent, &pno); + if (err) + goto out; + if (pno->p_base->pb_ino) { + err = -EEXIST; + goto error; + } + + if (IS_RDONLY(pno, pno->p_base->pb_ino)) { + err = -EROFS; + goto error; + } + err = + (*pno->p_parent->p_base->pb_ino->i_ops.inop_symlink)(pno, oldpath); +error: + P_RELE(pno); +out: + SYSIO_INTERFACE_RETURN(err ? -1 : 0, err); +} + +#ifdef REDSTORM +#undef __symlink +sysio_sym_weak_alias(SYSIO_INTERFACE_NAME(symlink), + PREPEND(__, SYSIO_INTERFACE_NAME(symlink))) +#endif diff --git a/libsysio/src/truncate.c b/libsysio/src/truncate.c new file mode 100644 index 0000000..718f0af --- /dev/null +++ b/libsysio/src/truncate.c @@ -0,0 +1,157 @@ +/* + * This Cplant(TM) source code is the property of Sandia National + * Laboratories. + * + * This Cplant(TM) source code is copyrighted by Sandia National + * Laboratories. + * + * The redistribution of this Cplant(TM) source code is subject to the + * terms of the GNU Lesser General Public License + * (see cit/LGPL or http://www.gnu.org/licenses/lgpl.html) + * + * Cplant(TM) Copyright 1998-2003 Sandia Corporation. + * Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive + * license for use of this work by or on behalf of the US Government. + * Export of this program may require a license from the United States + * Government. + */ + +/* + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Questions or comments about this library should be sent to: + * + * Lee Ward + * Sandia National Laboratories, New Mexico + * P.O. Box 5800 + * Albuquerque, NM 87185-1110 + * + * lee@sandia.gov + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "sysio.h" +#include "inode.h" +#include "file.h" + +#include "sysio-symbols.h" + +/* + * Truncate file, given path (alias) or index node. + */ +static int +do_truncate(struct pnode *pno, struct inode *ino, _SYSIO_OFF_T length) +{ + struct intnl_stat stbuf; + unsigned mask; + + if (length < 0) + return -EINVAL; + + if (!ino && pno->p_base->pb_ino) + ino = pno->p_base->pb_ino; + if (!ino) + return -EBADF; + if (S_ISDIR(ino->i_mode)) /* for others too? */ + return -EISDIR; + if (!S_ISREG(ino->i_mode)) + return -EINVAL; + + (void )memset(&stbuf, 0, sizeof(stbuf)); + stbuf.st_size = length; + mask = SETATTR_LEN; + return _sysio_setattr(pno, ino, mask, &stbuf); +} + +static int +PREPEND(_, SYSIO_INTERFACE_NAME(truncate))(const char *path, + _SYSIO_OFF_T length) +{ + int err; + struct pnode *pno; + SYSIO_INTERFACE_DISPLAY_BLOCK; + + SYSIO_INTERFACE_ENTER; + err = _sysio_namei(_sysio_cwd, path, 0, NULL, &pno); + if (err) + goto out; + err = do_truncate(pno, pno->p_base->pb_ino, length); + P_RELE(pno); + +out: + SYSIO_INTERFACE_RETURN(err ? -1 : 0, err); +} + +#if _LARGEFILE64_SOURCE +#undef truncate64 +sysio_sym_weak_alias(PREPEND(_, SYSIO_INTERFACE_NAME(truncate)), + SYSIO_INTERFACE_NAME(truncate64)) + +#undef truncate +int +SYSIO_INTERFACE_NAME(truncate)(const char *path, off_t length) +{ + + return PREPEND(_, SYSIO_INTERFACE_NAME(truncate))(path, length); +} +#else +#undef truncate +sysio_sym_weak_alias(PREPEND(_, SYSIO_INTERFACE_NAME(truncate)), + SYSIO_INTERFACE_NAME(truncate)) +#endif + +static int +PREPEND(_, SYSIO_INTERFACE_NAME(ftruncate))(int fd, _SYSIO_OFF_T length) +{ + int err; + struct file *fil; + SYSIO_INTERFACE_DISPLAY_BLOCK; + + SYSIO_INTERFACE_ENTER; + err = 0; + fil = _sysio_fd_find(fd); + if (!fil) { + err = -EBADF; + goto out; + } + err = do_truncate(NULL, fil->f_ino, length); +out: + SYSIO_INTERFACE_RETURN(err ? -1 : 0, err); +} + +#if _LARGEFILE64_SOURCE +#undef ftruncate64 +sysio_sym_weak_alias(PREPEND(_, SYSIO_INTERFACE_NAME(ftruncate)), + SYSIO_INTERFACE_NAME(ftruncate64)) + +#undef ftruncate +int +SYSIO_INTERFACE_NAME(ftruncate)(int fd, off_t length) +{ + + return PREPEND(_, SYSIO_INTERFACE_NAME(ftruncate))(fd, length); +} +#else +#undef ftruncate +sysio_sym_weak_alias(PREPEND(_, SYSIO_INTERFACE_NAME(ftruncate)), + SYSIO_INTERFACE_NAME(ftruncate)) +#endif diff --git a/libsysio/src/unlink.c b/libsysio/src/unlink.c new file mode 100644 index 0000000..c584fcc --- /dev/null +++ b/libsysio/src/unlink.c @@ -0,0 +1,103 @@ +/* + * This Cplant(TM) source code is the property of Sandia National + * Laboratories. + * + * This Cplant(TM) source code is copyrighted by Sandia National + * Laboratories. + * + * The redistribution of this Cplant(TM) source code is subject to the + * terms of the GNU Lesser General Public License + * (see cit/LGPL or http://www.gnu.org/licenses/lgpl.html) + * + * Cplant(TM) Copyright 1998-2003 Sandia Corporation. + * Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive + * license for use of this work by or on behalf of the US Government. + * Export of this program may require a license from the United States + * Government. + */ + +/* + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Questions or comments about this library should be sent to: + * + * Lee Ward + * Sandia National Laboratories, New Mexico + * P.O. Box 5800 + * Albuquerque, NM 87185-1110 + * + * lee@sandia.gov + */ + +#include +#include +#include +#include +#include + +#include "sysio.h" +#include "inode.h" +#include "fs.h" +#include "mount.h" +#include "sysio-symbols.h" + +int +SYSIO_INTERFACE_NAME(unlink)(const char *path) +{ + struct intent intent; + int err; + struct pnode *pno; + struct inode *ino; + SYSIO_INTERFACE_DISPLAY_BLOCK; + + SYSIO_INTERFACE_ENTER; + INTENT_INIT(&intent, INT_UPDPARENT, NULL, NULL); + err = _sysio_namei(_sysio_cwd, path, ND_NOFOLLOW, &intent, &pno); + if (err) + goto out; + ino = pno->p_base->pb_ino; + if (IS_RDONLY(pno, ino)) { + err = -EROFS; + goto error; + } + err = (*ino->i_ops.inop_unlink)(pno); + if (err) + goto error; + assert(pno->p_base->pb_ino); + /* + * Invalidate the path node. + */ + ino = pno->p_base->pb_ino; + pno->p_base->pb_ino = NULL; + /* + * Kill the i-node. I've thought and thought about this. We + * can't allow it to be found via namei any longer because we + * can't count on generation numbers support and have no + * clue why there might be other soft-references -- Could + * be an open file. + */ + I_GONE(ino); + +error: + P_RELE(pno); +out: + SYSIO_INTERFACE_RETURN(err ? -1 : 0, err); +} + +#ifdef REDSTORM +#undef __unlink +sysio_sym_weak_alias(SYSIO_INTERFACE_NAME(unlink), + PREPEND(__, SYSIO_INTERFACE_NAME(unlink))) +#endif diff --git a/libsysio/src/utime.c b/libsysio/src/utime.c new file mode 100644 index 0000000..1124663 --- /dev/null +++ b/libsysio/src/utime.c @@ -0,0 +1,86 @@ +/* + * This Cplant(TM) source code is the property of Sandia National + * Laboratories. + * + * This Cplant(TM) source code is copyrighted by Sandia National + * Laboratories. + * + * The redistribution of this Cplant(TM) source code is subject to the + * terms of the GNU Lesser General Public License + * (see cit/LGPL or http://www.gnu.org/licenses/lgpl.html) + * + * Cplant(TM) Copyright 1998-2003 Sandia Corporation. + * Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive + * license for use of this work by or on behalf of the US Government. + * Export of this program may require a license from the United States + * Government. + */ + +/* + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Questions or comments about this library should be sent to: + * + * Lee Ward + * Sandia National Laboratories, New Mexico + * P.O. Box 5800 + * Albuquerque, NM 87185-1110 + * + * lee@sandia.gov + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "sysio.h" +#include "inode.h" +#include "file.h" + +int +SYSIO_INTERFACE_NAME(utime)(const char *path, const struct utimbuf *buf) +{ + int err; + struct pnode *pno; + struct utimbuf _utbuffer; + struct intnl_stat stbuf; + SYSIO_INTERFACE_DISPLAY_BLOCK; + + SYSIO_INTERFACE_ENTER; + err = _sysio_namei(_sysio_cwd, path, 0, NULL, &pno); + if (err) + goto out; + if (!buf) { + _utbuffer.actime = _utbuffer.modtime = time(NULL); + buf = &_utbuffer; + } + (void )memset(&stbuf, 0, sizeof(struct intnl_stat)); + stbuf.st_atime = buf->actime; + stbuf.st_mtime = buf->modtime; + err = + _sysio_setattr(pno, + pno->p_base->pb_ino, + SETATTR_ATIME | SETATTR_MTIME, + &stbuf); + P_RELE(pno); +out: + SYSIO_INTERFACE_RETURN(err ? -1 : 0, err); +} diff --git a/libsysio/tests/Makefile.am b/libsysio/tests/Makefile.am new file mode 100644 index 0000000..85c4304 --- /dev/null +++ b/libsysio/tests/Makefile.am @@ -0,0 +1,114 @@ +noinst_PROGRAMS = test_copy test_stats test_path test_list \ + test_getcwd test_link test_unlink test_rename \ + test_regions test_driver + +CLEANFILES=drv_data.c + +if WITH_NATIVE_DRIVER +NATIVE_DRIVER_NAME=native +NATIVE_DRIVER_CFLAGS= -I$(top_srcdir)/drivers/native +else +NATIVE_DRIVER_NAME= +NATIVE_DRIVER_CFLAGS= +endif + +if WITH_INCORE_DRIVER +INCORE_DRIVER_NAME=incore +INCORE_DRIVER_CFLAGS= -I$(top_srcdir)/drivers/incore +else +INCORE_DRIVER_NAME= +INCORE_DRIVER_CFLAGS= +endif + +if WITH_CPLANT_YOD +YOD_DRIVER_NAME=yod +YOD_DRIVER_CFLAGS= -DCPLANT_YOD +else +YOD_DRIVER_NAME= +YOD_DRIVER_CFLAGS= +endif + +if WITH_SOCKETS_DRIVER +SOCKETS_DRIVER_NAME=sockets +SOCKETS_DRIVER_CFLAGS= -I$(top_srcdir)/drivers/sockets +else +SOCKETS_DRIVER_NAME= +SOCKETS_DRIVER_CFLAGS= +endif + +DRIVERS=$(NATIVE_DRIVER_NAME) $(INCORE_DRIVER_NAME) $(YOD_DRIVER_NAME) \ + $(STFD_DEV_NAME) $(SOCKETS_DRIVER_NAME) + +CMNSRC=startup.c drv_init_all.c drv_data.c + +BUILT_SOURCES=drv_data.c +check_PROGRAMS=test_driver +if TEST_ALPHA_ARG +TESTS_ENVIRONMENT=IS_ALPHA=yes +else +TESTS_ENVIRONMENT=IS_ALPHA=no +endif +TESTS=test_all.pl + +CFL=$(AM_CFLAGS) $(AM_CPPFLAGS) \ + $(NATIVE_DRIVER_CFLAGS) $(INCORE_DRIVER_CFLAGS) \ + $(STDFD_DEV_CFLAGS) $(YOD_DRIVER_CFLAGS) + +LIBS=$(LIBBUILD_DIR)/libsysio.a + +test_copy_SOURCES=test_copy.c $(CMNSRC) +test_copy_CFLAGS=$(CFL) +test_copy_LDADD=$(LIBS) +test_copy_DEPENDENCIES=$(LIBS) + +test_stats_SOURCES=test_stats.c $(CMNSRC) +test_stats_CFLAGS=$(CFL) +test_stats_LDADD=$(LIBS) +test_stats_DEPENDENCIES=$(LIBS) + +test_path_SOURCES=test_path.c $(CMNSRC) +test_path_CFLAGS=$(CFL) +test_path_LDADD=$(LIBS) +test_path_DEPENDENCIES=$(LIBS) + +test_list_SOURCES=test_list.c $(CMNSRC) +test_list_CFLAGS=$(CFL) +test_list_LDADD=$(LIBS) +test_list_DEPENDENCIES=$(LIBS) + +test_getcwd_SOURCES=test_getcwd.c $(CMNSRC) +test_getcwd_CFLAGS=$(CFL) +test_getcwd_LDADD=$(LIBS) +test_getcwd_DEPENDENCIES=$(LIBS) + +test_link_SOURCES=test_link.c $(CMNSRC) +test_link_CFLAGS=$(CFL) +test_link_LDADD=$(LIBS) +test_link_DEPENDENCIES=$(LIBS) + +test_unlink_SOURCES=test_unlink.c $(CMNSRC) +test_unlink_CFLAGS=$(CFL) +test_unlink_LDADD=$(LIBS) +test_unlink_DEPENDENCIES=$(LIBS) + +test_rename_SOURCES=test_rename.c $(CMNSRC) +test_rename_CFLAGS=$(CFL) +test_rename_LDADD=$(LIBS) +test_rename_DEPENDENCIES=$(LIBS) + +test_regions_SOURCES=test_regions.c $(CMNSRC) +test_regions_CFLAGS=$(CFL) +test_regions_LDADD=$(LIBS) +test_regions_DEPENDENCIES=$(LIBS) + +test_driver_SOURCES=test_driver.c sysio_tests.c sysio_stubs.c help.c $(CMNSRC) +test_driver_CFLAGS=$(CFL) +test_driver_LDADD=$(LIBS) +test_driver_DEPENDENCIES=$(LIBS) + +drv_data.c: $(CONFIG_DEPENDENCIES) $(top_srcdir)/tests/gendrvdata.sh + test -z "drv_data.c" && rm -f drv_data.c; \ + $(SHELL) $(top_srcdir)/tests/gendrvdata.sh $(DRIVERS) > drv_data.c + +AM_CFLAGS = -L$(LIBBUILD_DIR) +include $(top_srcdir)/Rules.make diff --git a/libsysio/tests/README b/libsysio/tests/README new file mode 100644 index 0000000..a8cb7a8 --- /dev/null +++ b/libsysio/tests/README @@ -0,0 +1,185 @@ +To run the tests, just do a "make check" in the tests subdirectory. +On the CPlant alpha systems, 3 of the 7 tests in test_all.pl are excluded +due to known problems (problems as of the date of writing this; they +may have since been fixed). You can also manually run the individual +tests or ./test_all.pl. If you are running on CPlant, you need to +run test_all.pl with a -alpha argument. Either "make check" or +test_all.pl will run the 7 basic functionality tests (explained +below) and report the total number of passes and failures. +number of passes and failures. + +-----------------------SCRIPTS--------------------------------- + +There are a total of 8 scripts: test_copy.pl, test_list.pl, +test_getcwd.pl, test_stats.pl, test_stdfd.pl, test_path.pl, +populator.pl, and verifier.pl. All but the last two scripts +are ran with the test_all.pl script. Here is an explanation +of the scripts. All scripts take an optional "-alpha" arg +for running the scripts in an alpha/cplant environment. The +alpha arg makes certain assumptions about the running of the +environment; for example, it does not initilization and it +starts off the test driver with yod. + +test_copy.pl : 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] : This comes in two forms. +test_list.pl [-p] : 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 : Tests getcwd by verifying that setting the current + : working directory to dir and then calling getcwd + : returns dir + +test_stats.pl : 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 : Verified that stdin, stdout, and stderr can be opened and + : either written to or read from + +test_path.pl ... : 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 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 + +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 : 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 : Lists contents of dir. If no dir is given, uses cwd + +debug : Sets debug level to num + +sizeof : 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 : Issues a strcmp call on the two buffers to + : see if they are the same. Returns 0 for a + : match diff --git a/libsysio/tests/cleanup.pl b/libsysio/tests/cleanup.pl new file mode 100755 index 0000000..029286d --- /dev/null +++ b/libsysio/tests/cleanup.pl @@ -0,0 +1,96 @@ +#!/usr/bin/perl -w + +use IPC::Open2; + +use strict; +use FindBin; +use lib "$FindBin::Bin"; +use helper; + +sub usage +{ + print "Usage: ./cleanup.pl : Remove system directories used for test\n"; + exit(-1); +} + +sub do_remove +{ + my ($cmdfh, $outfh, $type, $cwd, $lastdir) = @_; + my $cmd; + if ($type eq "dir") { + $cmd = "rmdir"; + } else { + $cmd = "unlink"; + } + my $cmdstr = "CALL $cmd $cwd/$lastdir\n"; + + # Now remove the file/dir + helper::send_cmd($cmdfh, $outfh, $cmd, $cmdstr); + + # Verify the directory was made correctly + helper::verify_cmd($cmdfh, $outfh, $cmd); + } + + +my $currarg = 0; +my $is_alpha = 0; +my $alpha_arg = ""; +if (@ARGV == 0) { + usage(); +} +if ((@ARGV > 1) && ($ARGV[$currarg++] eq "-alpha")){ + $is_alpha = 1; + $alpha_arg = $ARGV[$currarg-1]; +} + +my $cwd = $ARGV[$currarg]; + +# Get tests directory +my $testdir = $FindBin::Bin; + +eval { + if ($is_alpha == 0) { + open2(\*OUTFILE, \*CMDFILE, "$testdir/test_driver --np"); + } else { + open2(\*OUTFILE, \*CMDFILE, + "yod -batch -quiet -sz 1 $testdir/test_driver --np"); + } +}; + +if ($@) { + if ($@ =~ /^open2/) { + warn "open2 failed: $!\n$@\n"; + return; + } + die; +} + +my $outfh = \*OUTFILE; +my $cmdfh = \*CMDFILE; + +if ($is_alpha == 0) { + helper::send_cmd($cmdfh, $outfh, "init", "CALL init\n"); +} + +# Remove the helper.pms +do_remove($cmdfh, $outfh, "file", $cwd, "tmp_dir/helper.pm"); +do_remove($cmdfh, $outfh, "file", $cwd, "tmp_dir/test1/helper.pm"); + +# Remove directories +do_remove($cmdfh, $outfh, "dir", $cwd, "tmp_dir/test1"); +do_remove($cmdfh, $outfh, "dir", $cwd, "tmp_dir/test2"); +do_remove($cmdfh, $outfh, "dir", $cwd, "tmp_dir"); + +print $cmdfh "exit\n"; +close $outfh; + +# Give test_driver time to finish +sleep 0.000001; + +print STDOUT "cleanup successful\n"; + +exit 0; + + + + diff --git a/libsysio/tests/drv_init_all.c b/libsysio/tests/drv_init_all.c new file mode 100644 index 0000000..6a3ad2b --- /dev/null +++ b/libsysio/tests/drv_init_all.c @@ -0,0 +1,23 @@ +#include + +extern int (*drvinits[])(void); + +/* + * Init all the drivers we know about. + */ +int +drv_init_all() +{ + int (**f)(void); + int err; + + err = 0; + f = drvinits; + while (*f) { + err = (**f++)(); + if (err) + return err; + } + + return 0; +} diff --git a/libsysio/tests/gendrvdata.sh b/libsysio/tests/gendrvdata.sh new file mode 100644 index 0000000..8b84d82 --- /dev/null +++ b/libsysio/tests/gendrvdata.sh @@ -0,0 +1,61 @@ +#!/bin/sh + +# This Cplant(TM) source code is the property of Sandia National +# Laboratories. +# +# This Cplant(TM) source code is copyrighted by Sandia National +# Laboratories. +# +# The redistribution of this Cplant(TM) source code is subject to the +# terms of the GNU Lesser General Public License +# (see cit/LGPL or http://www.gnu.org/licenses/lgpl.html) +# +# Cplant(TM) Copyright 1998-2003 Sandia Corporation. +# Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive +# license for use of this work by or on behalf of the US Government. +# Export of this program may require a license from the United States +# Government. + +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# Questions or comments about this library should be sent to: +# +# Lee Ward +# Sandia National Laboratories, New Mexico +# P.O. Box 5800 +# Albuquerque, NM 87185-1110 +# +# lee@sandia.gov + +echo '/*' +echo ' * This file automatically generated by gendrvdata.sh. All changes' +echo ' * will be lost!' +echo ' */' +echo +echo '#include ' +echo +echo '#include "test.h"' +echo +for i in $@; do + echo "extern int _sysio_${i}_init(void);" +done +echo +echo 'int (*drvinits[])(void) = {' + +for i in $@; do + echo " _sysio_${i}_init," +done +echo " NULL" +echo "};" diff --git a/libsysio/tests/help.c b/libsysio/tests/help.c new file mode 100644 index 0000000..ad5a769 --- /dev/null +++ b/libsysio/tests/help.c @@ -0,0 +1,551 @@ +#include +#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 \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] : 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 : 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 : 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] : 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] : 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] : Issue the ioctl command cmd on the file with file\n"); + fprintf(outfp, " : descriptor fd. Any arguments are placed in args\n"); + fprintf(outfp, " : At the moment, the only commands understand are the \n"); + fprintf(outfp, " : ioctl commands found in /usr/include/linux/fs.h\n"); +} + +void usage_umask() +{ + fprintf(outfp, "ioctl [mask] : Sets the umask used by open to set initial file permissions on\n"); + fprintf(outfp, " : a newly created file. Returnds the previous value of the mask\n"); +} + +void usage_iodone() +{ + fprintf(outfp, "iodone [ioid] : Poll for completion of the asynchronous request identifed by\n"); + fprintf(outfp, " : ioid. Returns 1 if request finished\n"); +} + +void usage_iowait() +{ + fprintf(outfp, "iowait [ioid] : Wait for completion of the asynchronous request identifed by\n"); + fprintf(outfp, " : ioid. Returns result of asynchronous request \n"); +} + +void usage_ipreadv() +{ + fprintf(outfp, "ipreadv [fd] [buf] [count] [off]: Reads data asynchrously to file descriptor fd \n"); + fprintf(outfp, " : starting at offset off. Data comes from \n"); + fprintf(outfp, " : buffer described by buf, which is a pointer to\n"); + fprintf(outfp, " : an iovec strucutre. Number of buffers is \n"); + fprintf(outfp, " : specified by count. Returns an iod_t on \n"); + fprintf(outfp, " : success and -1 on failure\n"); +} + +void usage_ipread() +{ + fprintf(outfp, "ipread [fd] [buf] [count] [off]: Read asynchrously up to count bytes from file\n"); + fprintf(outfp, " : with file descriptor fd starting at offset off\n"); + fprintf(outfp, " : Read into buffer pointed at by buf. Returns\n"); + fprintf(outfp, " : an iod_t on success and -1 on failure\n"); +} + +void usage_preadv() +{ + fprintf(outfp, "preadv [fd] [buf] [count] [off]: Reads data from file descriptor fd starting at\n"); + fprintf(outfp, " : offset off. Data goes into buffer described\n"); + fprintf(outfp, " : by buf, which is a pointer to an iovec \n"); + fprintf(outfp, " : structure. Number of buffers is specified by\n"); + fprintf(outfp, " : count. Returns the number of bytes read\n"); +} + +void usage_pread() +{ + fprintf(outfp, "preadv [fd] [buf] [count] [off]: Reads count bytes of data from file descriptor\n"); + fprintf(outfp, " : fd starting at offset off. Data goes into buf.\n"); + fprintf(outfp, " : Returns number of bytes read or -1 on failure\n"); +} + +void usage_ireadv() +{ + fprintf(outfp, "ireadv [fd] [buf] [count] : Reads data asynchrously to file descriptor fd \n"); + fprintf(outfp, " : Data comes from buffer described by buf, which is \n"); + fprintf(outfp, " : an pointer to an iovec structure. Number of\n"); + fprintf(outfp, " : buffers is specified by count. Returns an iod_t\n"); + fprintf(outfp, " : on success and -1 on failure\n"); +} + +void usage_iread() +{ + fprintf(outfp, "iread [fd] [buf] [count]: Read asynchrously up to count bytes from file with\n"); + fprintf(outfp, " : file descriptor fd into buffer pointed at by buf\n"); + fprintf(outfp, " : Returns an iod_t on success and -1 on failure\n"); +} + +void usage_readv() +{ + fprintf(outfp, "readv [fd] [buf] [count] : Reads data from file descriptor fd. Data comes from\n"); + fprintf(outfp, " : the buffer described by buf, which is a pointer to an\n"); + fprintf(outfp, " : an iovec structure. Number of buffers is specified\n"); + fprintf(outfp, " : by count. Returns the number of bytes read on \n"); + fprintf(outfp, " : on success and -1 on failure\n"); +} + +void usage_read() +{ + fprintf(outfp, "read [fd] [buf] [count]: Read up to count bytes from file with file \n"); + fprintf(outfp, " : descriptor fd into buffer pointed at by buf\n"); + fprintf(outfp, " : Returns number of bytes read on success or 0 on \n"); + fprintf(outfp, " : on failure\n"); +} + +void usage_ipwritev() +{ + fprintf(outfp, "ipwritev [fd] [buf] [count] [off]: writes data asynchronously to file with file\n"); + fprintf(outfp, " : descriptor fd starting at offset off. Data \n"); + fprintf(outfp, " : comes from buffers described by buf, which\n"); + fprintf(outfp, " : is a pointer to an iovec structure. Number \n"); + fprintf(outfp, " : of buffers is specified by count. Returns\n"); + fprintf(outfp, " : an iod_t on success and -1 on failure\n"); +} + +void usage_ipwrite() +{ + fprintf(outfp, "ipwrite [fd] [buf] [count] [off]: writes count bytes of data asynchronously to\n"); + fprintf(outfp, " : file with file descriptor fd starting at \n"); + fprintf(outfp, " : offset off. Data comes from buf. Returns an\n"); + fprintf(outfp, " : iod_t on success and -1 on failure\n"); +} + +void usage_pwritev() +{ + fprintf(outfp, "pwritev [fd] [buf] [count] [off]: writes data to file with file descriptor fd\n"); + fprintf(outfp, " : starting at offset off. Data comes from \n"); + fprintf(outfp, " : buffers described by buf, which is a pointer\n"); + fprintf(outfp, " : to an iovec structure. Number of buffers is\n"); + fprintf(outfp, " : by count. Returns number of bytes read on \n"); + fprintf(outfp, " : success and -1 on failure\n"); +} + +void usage_pwrite() +{ + fprintf(outfp, "pwrite [fd] [buf] [count] [off]: writes count bytes of data to file with file \n"); + fprintf(outfp, " : descriptor fd starting at offset off. Data\n"); + fprintf(outfp, " : Data comes from buf. Returns number of bytes\n"); + fprintf(outfp, " : written on success and -1 on failure\n"); +} + +void usage_iwritev() +{ + fprintf(outfp, "iwritev [fd] [buf] [count] : writes data asynchronously to file with file\n"); + fprintf(outfp, " : descriptor fd. Data comes from buffers described\n"); + fprintf(outfp, " : by buf, which is a pointer to an iovec structure.\n"); + fprintf(outfp, " : Number of buffers is specified by count. Returns\n"); + fprintf(outfp, " : an iod_t on success and -1 on failure\n"); +} + +void usage_iwrite() +{ + fprintf(outfp, "iwrite [fd] [buf] [count] : writes count bytes of data asynchronously to\n"); + fprintf(outfp, " : file with file descriptor fd. Data comes from buf.\n"); + fprintf(outfp, " : Returns an iod_t on success and -1 on failure.\n"); +} + +void usage_writev() +{ + fprintf(outfp, "writev [fd] [buf] [count]: writes data to file descriptor fd. Data comes from\n"); + fprintf(outfp, " : buffers described by buf, which is a pointer to a \n"); + fprintf(outfp, " : iovec strucutre. Number of buffers is specified by \n"); + fprintf(outfp, " : count \n"); +} + +void usage_write() +{ + fprintf(outfp, "write [fd] [buf] [count] : writes count bytes of data to file with file \n"); + fprintf(outfp, " : descriptor fd. Data comes from buf. Returns number\n"); + fprintf(outfp, " : of bytes written on success and -1 on failure.\n"); +} + +void usage_mknod() +{ + fprintf(outfp, "mknod [path] [mode] [dev] : creates a filesystem node named path with \n"); + fprintf(outfp, " : specified mode using device special file dev\n"); + fprintf(outfp, " : Returns 0 on sucess and -1 on failure\n"); +} + + +void usage_umount() +{ + fprintf(outfp, "umount [path] : Umount file at path. Returns 0 on success and -1 on failure\n"); +} + +void usage_init_iovec() +{ + fprintf(outfp, "init_iovec buf offset len num iov_buf: Init iovector. iov_uf points to an array of\n"); + fprintf(outfp, " iovecs, num is the number of the iovec, \n"); + fprintf(outfp, " buf is the buffer to be used, offset \n"); + fprintf(outfp, " specifies how far into the buffer the iovec\n"); + fprintf(outfp, " should point and len is the iov length\n"); +} + +void usage_init_xtvec() +{ + fprintf(outfp, "init_xtvec offset len num buf: Init xtvector. Buf points to an array of\n"); + fprintf(outfp, " xtvecs, num is the number of the xtvec, offset\n"); + fprintf(outfp, " is xtv_off and len is the iov lenghth\n"); + fprintf(outfp, " the iov length\n"); +} + +void usage_writex() +{ + fprintf(outfp, "writex fd iovs iov_cnt xtvs xtvcnt: Write iov_cnt iovecs out to file using\n"); + fprintf(outfp, " xtvcnt xtvecs\n"); +} + +void usage_iwritex() +{ + fprintf(outfp, "iwritex fd iovs iov_cnt xtvs xtvcnt: Write iov_cnt iovecs out to file using\n"); + fprintf(outfp, " xtvcnt xtvecs\n"); +} + +void usage_readx() +{ + fprintf(outfp, "readx fd iovs iov_cnt xtvs xtvcnt: Read iov_cnt iovecs out from file using\n"); + fprintf(outfp, " xtvcnt xtvecs\n"); +} + +void usage_ireadx() +{ + fprintf(outfp, "ireadx fd iovs iov_cnt xtvs xtvcnt: Read iov_cnt iovecs out from file using\n"); + fprintf(outfp, " xtvcnt xtvecs\n"); +} + + +void usage_checkbuf() +{ + fprintf(outfp, "checkbuf [buf] [size] [val] [off]: Staring at offset off, checks to see\n"); + fprintf(outfp, " if val is in first size bytes of buf\n"); +} + +void usage_exit() +{ +} diff --git a/libsysio/tests/helper.pm b/libsysio/tests/helper.pm new file mode 100644 index 0000000..306c40e --- /dev/null +++ b/libsysio/tests/helper.pm @@ -0,0 +1,130 @@ +#!/usr/bin/perl -w + +# +# Provides a set of helper routines for use in the Perl +# test scripts +# + +package helper; +use strict; +use POSIX; + +BEGIN{} + +# Print out a given error message, close the command file +# and exit +sub print_and_exit +{ + my ($cmdfh, $outfh, $exit_num, $exit_str) = @_; + + print STDOUT "$exit_str"; + + # Clean up + my $cmdstr = 'FREE $buf'; + $cmdstr = $cmdstr."\n"; + + print $cmdfh $cmdstr; + + my $res = <$outfh>; + chop($res); + + print $cmdfh "exit\n"; + close $outfh; + + # Give test_driver time to finish + sleep 0.000001; + + exit $exit_num; +} + + +# Output the given command and make sure that the exit +# code for the command was valid +sub send_cmd +{ + my ($cmdfh, $outfh, $cmd, $cmdstr) = @_; + + print $cmdfh $cmdstr; + + my $res = <$outfh>; + chop($res); + if ($res ne "0000 ") { + print_and_exit($cmdfh, $outfh, 1, "ERROR! Command $cmd failed with code $res\n"); + } +} + +# Check the return value from the last libsysio call +sub verify_cmd +{ + + my ($cmdfh, $outfh, $cmd) = @_; + + # Verify the system call's output + my $cmdstr = 'PRINT $$'; + $cmdstr .= "\n"; + send_cmd($cmdfh, $outfh, "PRINT", $cmdstr); + + my $res = <$outfh>; + chop($res); + + if ($res eq "0xffffffff") { + + # Get the errno + $cmdstr = 'PRINT $errno'; + $cmdstr .= "\n"; + send_cmd($cmdfh, $outfh, "PRINT", $cmdstr); + + my $err = <$outfh>; + chop($err); + print_and_exit($cmdfh, $outfh, 1, "ERROR! $cmd returned $err\n"); + } + return $res; +} + +# Compares two numbers. Output error message and exit if +# they differ +sub cmp_nums +{ + my ($cmdfh, $outfh, $ionum, $pnum, $desc) = @_; + + my $str; + if (!defined($ionum)) { + print_and_exit($cmdfh, $outfh, 1, "ERROR! ionum for $desc undefined"); + } elsif (!defined($pnum)) { + print_and_exit($cmdfh, $outfh, 1, "ERROR! pnum for $desc undefined"); + } + if ($ionum != $pnum) { + my $str = sprintf("ERROR! Sysio's number %x does not match Perl's (%x)\n", + $ionum, $pnum); + $str = sprintf("%s Numbers were %s\n", $str, $desc); + print_and_exit($cmdfh, $outfh, 1, $str); + } +} + +sub get_type +{ + my $mode = $_[0]; + my $t = '?'; + + if (S_ISDIR($mode)) { + $t = 'd'; + } elsif (S_ISCHR($mode)) { + $t = 'c'; + } elsif (S_ISBLK($mode)) { + $t = 'b'; + } elsif (S_ISREG($mode)) { + $t = 'f'; + } elsif (S_ISFIFO($mode)) { + $t = 'p'; + } elsif (S_ISLNK($mode)) { + $t = 'S'; + } elsif (S_ISSOCK($mode)) { + $t = 's'; + } + + return $t; +} + +END{} + +1; diff --git a/libsysio/tests/module.mk b/libsysio/tests/module.mk new file mode 100644 index 0000000..b6ed491 --- /dev/null +++ b/libsysio/tests/module.mk @@ -0,0 +1,2 @@ +TESTS_EXTRA = $(shell ls tests/*.[ch] tests/*.sh tests/*.p[lm]) \ + tests/Makefile.am tests/Makefile.in tests/module.mk diff --git a/libsysio/tests/populator.pl b/libsysio/tests/populator.pl new file mode 100755 index 0000000..b218519 --- /dev/null +++ b/libsysio/tests/populator.pl @@ -0,0 +1,155 @@ +#!/usr/bin/perl -w + +use IPC::Open2; + +use strict; +use helper; + +sub usage +{ + print "Usage: ./populator.pl <-seed seed> :\n"; + print " <-file filename> :\n"; + print " <-bytes bytes> : Create a file, filename, that\n"; + print " : is bytes long and populate with\n"; + print " : random numbers using the given\n"; + print " : seed. Will use defaults if args\n"; + print " : not given\n"; + exit(-1); +} + +sub get_buf +{ + my $MAX_SIZE = 2147483648; + + my $str; + my $num; + my $len = 0; + + while ($len < 512) { + $num = rand $MAX_SIZE; + my $tmpstr = sprintf("%d", $num); + $str .= $tmpstr; + $len += length $tmpstr; + } + + return ($len, $str); +} + +sub write_file +{ + my ($cmdfh, $outfh, $filename, $bytes) = @_; + + + # Allocate the read buffer + my $cmd = '$buf = ALLOC 1024'."\n"; + helper::send_cmd($cmdfh, $outfh, "alloc", $cmd); + + # Open (create) the new file + $cmd = '$fd = CALL open '."$filename O_RDWR|O_CREAT S_IRWXU\n"; + helper::send_cmd($cmdfh, $outfh, "open", $cmd); + + # Verify the system call's output + helper::verify_cmd($cmdfh, $outfh, "open"); + + my $left_bytes = $bytes; + while ($left_bytes > 0) { + # Get a buffer filled with random numbers + # Buffer will be no less than 512 bytes + my ($len, $buf) = get_buf; + if ($len > $left_bytes) { + $len = $left_bytes; + } + + # Need to fill $buf with the buffer + $cmd = "CALL fill $buf STR $len 0 ".'$buf'."\n"; + helper::send_cmd($cmdfh, $outfh, "fill", $cmd); + + # Write out $len bytes to $filename + $cmd = 'CALL write $fd $buf '."$len\n"; + + helper::send_cmd($cmdfh, $outfh, "write", $cmd); + + my $written_bytes = helper::verify_cmd($cmdfh, $outfh, "write"); + $written_bytes = oct($written_bytes); + if ($written_bytes != $len) { + helper::print_and_exit($cmdfh, $outfh, 1, + "ERROR! Meant to print out $len but only printed $written_bytes\n"); + } + + $left_bytes -= $len; + } +} + +sub populate_file +{ + my ($filename, $bytes, $is_alpha) = @_; + + eval { + if ($is_alpha == 0) { + open2(\*OUTFILE, \*CMDFILE, "./test_driver --np"); + } else { + open2(\*OUTFILE, \*CMDFILE, + "yod -batch -quiet -sz 1 ./test_driver --np"); + } + }; + + if ($@) { + if ($@ =~ /^open2/) { + warn "open2 failed: $!\n$@\n"; + return; + } + die; + + } + + my $outfh = \*OUTFILE; + my $cmdfh = \*CMDFILE; + + if ($is_alpha == 0) { + helper::send_cmd($cmdfh, $outfh, "init", "CALL init\n"); + } + + # Now write the file + write_file($cmdfh, $outfh, $filename, $bytes); + + # Close the file + my $cmd = 'CALL close $fd'."\n"; + helper::send_cmd($cmdfh, $outfh, "close", $cmd); + + helper::verify_cmd($cmdfh, $outfh, "close"); + + # All done + helper::print_and_exit($cmdfh, $outfh, 0, "File $filename successfully created\n"); +} + + +my $is_alpha = 0; +my $seed = time; +my $filename = "randfile.$seed.$$"; +my $bytes = 1024; +for (my $i = 0; $i < @ARGV; $i++) +{ + if ($ARGV[$i] eq "-file") { + $i++; + $filename = $ARGV[$i]; + } elsif ($ARGV[$i] eq "-seed") { + $i++; + $seed = $ARGV[$i]; + } elsif ($ARGV[$i] eq "-alpha") { + $is_alpha = 1; + } elsif ($ARGV[$i] eq "-bytes") { + $i++; + $bytes = $ARGV[$i]; + } +} + +# seed the randome number generator +srand $seed; + +populate_file($filename, $bytes, $is_alpha); + +exit $seed; + + + + diff --git a/libsysio/tests/setup.pl b/libsysio/tests/setup.pl new file mode 100755 index 0000000..4270f59 --- /dev/null +++ b/libsysio/tests/setup.pl @@ -0,0 +1,104 @@ +#!/usr/bin/perl -w + +use IPC::Open2; + +use strict; +use FindBin; +use lib "$FindBin::Bin"; +use helper; + +sub usage +{ + print "Usage: ./setup.pl : Setup initial system directories for test\n"; + exit(-1); +} + +sub do_makedir +{ + my ($cmdfh, $outfh, $cwd, $lastdir) = @_; + my $cmd = "CALL mkdir $cwd/$lastdir 0777\n"; + + # Now create newdir + helper::send_cmd($cmdfh, $outfh, "mkdir", $cmd); + + # Verify the directory was made correctly + helper::verify_cmd($cmdfh, $outfh, "mkdir"); + } + + +my $currarg = 0; +my $is_alpha = 0; +my $alpha_arg = ""; +if (@ARGV == 0) { + usage(); +} +if ((@ARGV > 1) && ($ARGV[$currarg++] eq "-alpha")){ + $is_alpha = 1; + $alpha_arg = $ARGV[$currarg-1]; +} + +my $cwd = $ARGV[$currarg]; + +# Get tests directory +my $testdir = $FindBin::Bin; + +eval { + if ($is_alpha == 0) { + open2(\*OUTFILE, \*CMDFILE, "$testdir/test_driver --np"); + } else { + open2(\*OUTFILE, \*CMDFILE, + "yod -batch -quiet -sz 1 $testdir/test_driver --np"); + } +}; + +if ($@) { + if ($@ =~ /^open2/) { + warn "open2 failed: $!\n$@\n"; + return; + } + die; +} + +my $outfh = \*OUTFILE; +my $cmdfh = \*CMDFILE; + +if ($is_alpha == 0) { + helper::send_cmd($cmdfh, $outfh, "init", "CALL init\n"); +} + + +# Create tmp_dir +do_makedir($cmdfh, $outfh, $cwd, "tmp_dir"); +do_makedir($cmdfh, $outfh, $cwd, "tmp_dir/test1"); +do_makedir($cmdfh, $outfh, $cwd, "tmp_dir/test2"); + +# Copy helper.pm +print STDERR "Copying $testdir/helper.pm to $cwd/tmp_dir/test1/helper.pm\n"; +my $res = `perl $testdir/test_copy.pl $alpha_arg $testdir/helper.pm $cwd/tmp_dir/test1/helper.pm`; +chop($res); + +if ($res ne "copy test successful") { + print STDERR "setup (copy test) failed with message: $res\n"; + print $cmdfh "exit\n"; + close $outfh; + + # Give test_driver time to finish + sleep 0.000001; + + print STDOUT "Copying of helper.pm failed\n"; + exit 1; +} + + print $cmdfh "exit\n"; +close $outfh; + +# Give test_driver time to finish +sleep 0.000001; + +print STDOUT "setup successful\n"; + +exit 0; + + + + diff --git a/libsysio/tests/startup.c b/libsysio/tests/startup.c new file mode 100644 index 0000000..54c56d1 --- /dev/null +++ b/libsysio/tests/startup.c @@ -0,0 +1,27 @@ +#include +#include +#include +#include + +#include "sysio.h" + +#include "test.h" + +int +_test_sysio_startup() +{ + int err; + const char *s; + + err = _sysio_init(); + if (err) + return err; + err = drv_init_all(); + if (err) + return err; + s = getenv("SYSIO_NAMESPACE"); + err = s ? _sysio_boot(s) : -ENOTTY; + if (err) + return err; + return 0; +} diff --git a/libsysio/tests/sysio_stubs.c b/libsysio/tests/sysio_stubs.c new file mode 100644 index 0000000..2fc5046 --- /dev/null +++ b/libsysio/tests/sysio_stubs.c @@ -0,0 +1,2705 @@ +#define _BSD_SOURCE + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "test_driver.h" +#include "sysio.h" +#include "xtio.h" + +/* + * ################################################ + * # Function stubs # + * # These allow all of the different commands # + * # to be called with the same format # + * ################################################ + */ + +int test_do_setdebug(int argc, char **argv) +{ + int level; + + if (argc != 1) { + DBG(2, fprintf(outfp, "Invalid number of args (%d) for setdebug\n", + argc)); + return INVALID_ARGS; + } + + level = atoi(argv[0]); + + if (level < 0) { + DBG(2, fprintf(outfp, "Invalid debug level %d\n", level)); + return INVALID_ARGS; + } + + debug_level = level; + return SUCCESS; +} + +int test_do_printline(int argc, char **argv) +{ + int on; + + + if (argc != 1) { + DBG(2, fprintf(outfp, "Invalid number of args (%d) for printline\n", + argc)); + return INVALID_ARGS; + } + + on = atoi(argv[0]); + if (on) + print_line = 1; + else + print_line = 0; + + return SUCCESS; +} + +/* +int test_do_setoutput(int argc, char **argv) +{ + FILE *newfp; + + if (argc != 1) { + fprintf(outfp, "Invalid number of args (%d) for setoutput\n", + argc); + return -1; + } + + newfp = fopen(argv[0], "w"); + if (!newfp) { + fprintf(outfp, "Unable to open new output file %s\n", argv[0]); + return -1; + } + + outfp = newfp; + + return 0; +} + +*/ + + +int test_do_fillbuff(int argc, char **argv) +{ + char *typestr, *buf; + void *valptr; + int size, type, index, offset; + + if (argc != 5) { + DBG(2, + fprintf(outfp, + "fillbuff requires a value, a type, a size, an offset, and the target buffer\n")); + fprintf(stderr, "fillbuff requires 5 args, you gave %d\n", argc); + return INVALID_ARGS; + } + + offset = get_obj(argv[3]); + if (offset < 0) { + DBG(2, fprintf(outfp, "Do not understand offset %s\n", argv[3])); + return INVALID_VAR; + } + + index = get_obj(argv[4]); + if (index < 0) { + DBG(2, fprintf(outfp, "Can't find buffer at %s\n", argv[4])); + return INVALID_VAR; + } + buf = (char *)(buflist[index]->buf)+offset; + + DBG(4, fprintf(outfp, "Buffer start is at %p\n", (void *)buflist[index])); + + typestr = argv[1]; + size = get_obj(argv[2]); + if (size < 0) { + DBG(2, fprintf(outfp, "Unable to understand size %s\n", argv[2])); + return INVALID_VAR; + } + + if ( (!strcmp(typestr, "UINT")) || (!strcmp(typestr, "SINT")) ){ + int val = get_obj(argv[0]); + valptr = &val; + type = UINT; + if (val < 0) { /* FIX THIS */ + DBG(2, fprintf(outfp, "Can't understand value %s\n", argv[0])); + return INVALID_VAR; + } + DBG(4, fprintf(outfp, "Copying %d bytes from %p. Val is %x\n", + size, buf, *((int *)valptr))); + memcpy(buf, valptr, size); + + } else if (!strcmp(typestr,"STR")) { + type = STR; + valptr = argv[0]; + DBG(4, fprintf(outfp, "Copying %d bytes from %p. Val is %s\n", + size, buf, (char *)valptr)); + memcpy(buf, valptr, size); + } else if (!strcmp(typestr, "PTR")) { + unsigned long val; + int index = get_obj(argv[0]); + if (index < 0) { + DBG(2, fprintf(outfp, "Unable to find buffer at %s\n", argv[0])); + return INVALID_VAR; + } + + val = (unsigned long)buflist[index]->buf; + valptr = &val; + DBG(4, fprintf(outfp, "Copying %d bytes from %p. Val is %p\n", + size, buf, valptr)); + memcpy(buf, valptr, size); + } else { + DBG(2, fprintf(outfp, "Unknown type %s. Valid types are UINT, STR, and PTR\n", + typestr)); + fprintf(stderr, "Unknown type %s. Valid types are UINT, STR, and PTR\n", + typestr); + return INVALID_ARGS; + } + + return SUCCESS; +} + + +#define STR_TYPE 1 +#define INT_TYPE 2 +#define SHORT_TYPE 3 +#define CHAR_TYPE 4 +#define LONG_TYPE 5 + +void print_partial(char *buf, int offset, int len, int type) +{ + int i; + + if (type == STR_TYPE) { + sprintf(output, "%s%s", output, (char *)(buf+offset)); + DBG(4, fprintf(outfp, "Printing str %s\n", (char *)(buf+offset))); + } else { + if (type == SHORT_TYPE) { + for (i = 0; i < len; i+= 2) { + short *ibuf = (short *)(buf + offset + i); + sprintf(output, "%s%#04x ", output, *ibuf); + DBG(4, fprintf(outfp, "Printing short %#04x\n", *ibuf)); + } + } else if (type == CHAR_TYPE) { + for (i = 0; i < len; i++) { + short *ibuf = (short *)(buf+offset+i); + sprintf(output, "%s%#02x ", output, (*ibuf & 0x00ff)); + DBG(4, fprintf(outfp, "Printing char %c\n", (*ibuf & 0x00ff))); + } + } else if (type == INT_TYPE) { + for (i = 0; i < len; i+= 4) { + int *ibuf = (int *)(buf + offset + i); + sprintf(output, "%s%#08x ", output, *ibuf); + DBG(4, fprintf(outfp, "Printing int %#08x\n", *ibuf)); + } + } else { + for (i = 0; i < len; i += 8) { + unsigned long *lbuf = (unsigned long *)(buf + offset +i); + sprintf(output, "%s%#08lx ", output, *lbuf); + DBG(4, fprintf(outfp, "Printing int %#016lx\n", *lbuf)); + } + } + } +} + +int test_do_printbuf(int argc, char **argv) +{ + int index, i, type, offset, len; + struct buf_t *buf_st; + void *buf; + char *typestr; + struct var_mapping *mobj; + + if (argv[0][0] == '$') { + if (argv[0][1] == '$') { + sprintf(output, "\n%#010x", (unsigned int)last_ret_val); + return SUCCESS; + } else if (!strcmp("errno", &argv[0][1])) { + sprintf(output, "\n%#010x", my_errno); + return SUCCESS; + } + } + + mobj = get_map(argv[0]); + if (mobj == NULL) { + DBG(2, fprintf(outfp, "Can't get var at %s\n", argv[0])); + return INVALID_VAR; + } + + if (mobj->type == UINT) + sprintf(output, "\n%#010x", mobj->obj); + else if (mobj->type == SINT) + sprintf(output, "%d", mobj->obj); + else if ((mobj->type == STR) || (mobj->type == PTR)) { + index = mobj->obj; + + buf_st = buflist[index]; + DBG(2, fprintf(outfp, "buf_st is %p:\n", (void *)buf_st)); + buf = buf_st->buf; + DBG(2, fprintf(outfp, "buf %s:\n", argv[0])); + if (mobj->type == STR) { + sprintf(output, "\n%s", (char *)buf); + } else { + sprintf(output,"%s\n", output); + DBG(2, fprintf(outfp, "buf_st->len is %d, buf is %p\n", buf_st->len, buf)); + if (argc == 1) { + for (i = 0; i < buf_st->len/4; i++) + DBG(2, fprintf(outfp, "%#x ", ((int *)buf)[i])); + sprintf(output, "%s%#x ", output, ((int *)buf)[i]); + + } + + for (i = 1; i < argc; i++) { + offset = get_obj(argv[i++]); + len = get_obj(argv[i++]); + if ((offset < 0) || (len < 0)) { + DBG(2, fprintf(outfp, "Invalid offset (%s) or len (%s)\n", + argv[i-2], argv[i-1])); + return INVALID_VAR; + } + typestr = argv[i]; + if (!strcmp("STR", typestr)) + type = STR_TYPE; + else if (!strcmp("INT", typestr)) + type = INT_TYPE; + else if (!strcmp("SHORT", typestr)) + type = SHORT_TYPE; + else if (!strcmp("CHAR", typestr)) + type = CHAR_TYPE; + else if (!strcmp("LONG", typestr)) + type = LONG_TYPE; + else { + DBG(2, fprintf(outfp, "Unable to understand type %s\n", + typestr)); + return INVALID_ARGS; + } + print_partial(buf, offset, len, type); + } + } + } + DBG(3, fprintf(outfp, "output: %s \n", output)); + return SUCCESS; +} + +int test_do_mount(int argc, char **argv) +{ + if (argc != 2) { + DBG(2, fprintf(outfp, "Invalid number of args (%d) for test_do_mount\n", + argc)); + return INVALID_ARGS; + } + + DBG(4, fprintf(outfp, "Calling mount with from %s and to %s\n", + argv[0], argv[1])); + last_ret_val = sysio_mount(argv[0], argv[1]); + my_errno = errno; + last_type = SINT; + return SUCCESS; +} + +int test_do_clear(int argc, char **argv) +{ + int index; + struct buf_t *buf; + + if (argc != 1) { + DBG(2, fprintf(outfp, "Invalid number of args (%d) for clear\n", + argc)); + return INVALID_ARGS; + } + index = get_obj(argv[0]); + if (index < 0) { + fprintf(outfp, "Unable to locate buffer %s\n", + argv[0]); + return -1; + } + buf = buflist[index]; + bzero(buf->buf, buf->len); + + return SUCCESS; +} + +int test_do_list(int argc, char **argv) +{ + char *buf; + + if ((argc) && (argc != 1)) { + DBG(2, fprintf(outfp, "Invalid number of args (%d) for list\n", + argc)); + return INVALID_ARGS; + } + + DBG(5,fprintf(outfp, "In test_do_list with args %p\n", (void *)argv)); + if (!argv) { + buf = getcwd(NULL, 0); + DBG(4, fprintf(outfp, "Calling list with dir of %s\n", buf)); + last_ret_val = sysio_list(buf); + my_errno = errno; + free(buf); + return SUCCESS; + } + + last_type = SINT; + return sysio_list(*argv); +} + +/* + * Initlizes sysio library. Will use default initlization + * unless arguments are given + */ +int test_do_init(int argc, char **argv) +{ + if (argc > 0) { + char *rdriver; + char *mpath; + int mflags, rsize, msize; + if (argc != 3) { + DBG(2, fprintf(outfp, "Invalid number of args (%d) for init\n", + argc)); + return INVALID_ARGS; + } + + rdriver = get_str(argv[0]); + rsize = strlen(rdriver)+1; + if (rsize > 75) { + DBG(2, fprintf(outfp, "%s too long for root driver\n", rdriver)); + return INVALID_ARGS; + } + bzero(root_driver, 75); + memcpy(root_driver, rdriver, rsize); + + mpath = get_str(argv[1]); + msize = strlen(mpath)+1; + if (msize > 250) { + DBG(2, fprintf(outfp, "%s too long for mount path\n", mpath)); + return INVALID_ARGS; + } + bzero(mntpath, 250); + memcpy(mntpath, mpath, msize); + + mflags = get_obj(argv[2]); + if (mflags == -1) { + DBG(2, fprintf(outfp, "Invalid flags argument %s\n", argv[2])); + return INVALID_ARGS; + } + } + + DBG(5, fprintf(outfp, "In test_do_init\n")); + last_type = SINT; + DBG(3, fprintf(outfp, "initializing\n")); + return initilize_sysio(); +} + + +/* + * Returns 1 if the machine is big-endian, 0 + * otherwise + */ +int get_endian(int argc, char **argv) +{ + int x = 1; + + if ((argc) || (argv)) { + DBG(2, fprintf(outfp, "Expected no args for test_do_endian\n")); + return INVALID_ARGS; + } + + if(*(char *)&x == 1) { + /* little-endian, return 0 */ + last_ret_val= 0; + } else { + /* big endian, return 1 */ + last_ret_val= 1; + } + last_type = UINT; + return SUCCESS; +} + +int do_setbuf(int argc, char **argv) +{ + int val, size, index, offset; + void *buf; + + if (argc != 4) { + DBG(2, fprintf(outfp, "Need val, size, buffer, and offset for setbuf\n")); + return INVALID_ARGS; + } + val = get_obj(argv[0]); + if (val < 0) { + DBG(2, fprintf(outfp, "Unable to understand val of %s\n", + argv[0])); + return INVALID_VAR; + } + + size = get_obj(argv[1]); + if( size <=0 ) { + DBG(2, fprintf(outfp, "Size of %s is invalid\n", argv[1])); + return INVALID_VAR; + } + + index = get_obj(argv[2]); + if (index < 0) { + DBG(2, fprintf(outfp, "Unable to find buffer assocated with %s\n", + argv[2])); + return INVALID_VAR; + } + + buf = buflist[index]->buf; + + offset = get_obj(argv[3]); + + if (offset < 0) { + DBG(2, fprintf(outfp, "Unable to understand %s\n", argv[3])); + return INVALID_ARGS; + } + + buf = (void *)((char *)buf +offset); + + memset(buf, val, size); + + return SUCCESS; +} + + +int get_sizeof(int argc, char **argv) +{ + char *type; + int size; + + if (argc != 1) { + DBG(2, fprintf(outfp, "Number of args (%d) invalid for sizeof\n", + argc)); + return INVALID_ARGS; + } + + type = argv[0]; + + if (!strcmp(type, "char")) + size = sizeof(char); + else if (!strcmp(type, "int")) + size = sizeof(int); + else if (!strcmp(type, "long")) + size = sizeof(long); + else if (!strcmp(type, "flock")) + size = sizeof(struct flock); + else if (!strcmp(type, "stat")) + size = sizeof(struct stat); + else if (!strcmp(type, "statvfs")) + size = sizeof(struct statvfs); + else if (!strcmp(type, "iovec")) + size = sizeof(struct iovec); + else if (!strcmp(type, "xtvec")) + size = sizeof(struct xtvec); + else + return INVALID_ARGS; + + DBG(2, fprintf(outfp, "Size is %d\n", size)); + + last_type = UINT; + last_ret_val = size; + return SUCCESS; +} + +int test_do_exit(int argc, char **argv) +{ + int val = 0; + + if (argc) { + /* + * If argc is given, need to return the value of + * the passed in variable + */ + val = get_obj(argv[0]); + } + + /* + * Clean up. + */ + _sysio_shutdown(); + + if (argc) + DBG(3, printf("Exiting with %d from %s\n", val, argv[0])); + + exit(val); + + return 0; +} + +int get_buffer(int argc, char **argv) +{ + int size, align; + struct buf_t *buf; + + if (argc == 1) /* Just put size, not alignment */ + align = 16; + else if (argc == 2) + align = get_obj(argv[1]); + else { + DBG(2, fprintf(outfp, "Number of args (%d) invalid for alloc\n", + argc)); + return INVALID_ARGS; + } + + size = get_obj(argv[0]); + if (size < 0) { + DBG(2, fprintf(outfp, "Invalid size %s\n", argv[0])); + return INVALID_ARGS; + } + + DBG(3, fprintf(outfp, "Getting buffer of size %d and aligned at %d\n", + size, align)); + buf = (struct buf_t *)malloc(sizeof(struct buf_t)); + buf->buf = alloc_buff32(size, align); + buf->len = size; + buflist[next] = buf; + DBG(3, fprintf(outfp, "Your buffer (%p) (%p) is at index %d\n", + (void *)buf, buf->buf, next)); + next++; + + last_type = PTR; + last_ret_val = next-1; + return SUCCESS; +} + +int free_buffer(int argc, char **argv) +{ + int index; + char *name = argv[0]; + + if (argc != 1) { + DBG(2, fprintf(outfp, "Number of args (%d) invalid for free\n", + argc)); + return INVALID_ARGS; + } + + /* + * Assume that there is one arg and it + * is a variable name which maps to an + * index into the buffer array + */ + index = get_obj(name); + if (index < 0) { + DBG(2, fprintf(outfp, "Can't find buffer %s\n", + name)); + return INVALID_VAR; + } + DBG(4, fprintf(outfp, "Freeing buffer at index %d\n", index)); + free(buflist[index]); + + free_obj(name); + return SUCCESS; +} + +int cmp_bufs(int argc, char **argv) +{ + int res, index1, index2; + char *buf1, *buf2; + + if (argc != 2) { + fprintf(outfp, "Need two buffers to compare\n"); + return INVALID_ARGS; + } + + index1 = get_obj(argv[0]); + if (index1 < 0) { + fprintf(outfp, "Unable to locate buffer %s\n", + argv[0]); + return INVALID_VAR; + } + buf1 = buflist[index1]->buf; + + index2 = get_obj(argv[1]); + if (index2 < 0) { + fprintf(outfp, "Unable to locate buffer %s\n", + argv[1]); + return INVALID_VAR; + } + + buf2 = buflist[index2]->buf; + last_ret_val = strcmp(buf1, buf2); + + DBG(3, fprintf(outfp, "strcmp returned %d\n", res)); + return SUCCESS; +} + +int test_do_chdir(int argc, char **argv) +{ + if (argc != 1) { + DBG(2, fprintf(outfp, "Number of args (%d) invalid for chdir\n", + argc)); + return INVALID_ARGS; + } + last_type = SINT; + return sysio_chdir(argv[0]); +} + + +int test_do_chmod(int argc, char **argv) +{ + if (argc != 2) { + DBG(2, fprintf(outfp, "Number of args (%d) invalid for chmod\n", + argc)); + return INVALID_ARGS; + } + last_type = SINT; + return sysio_chmod(argv[0], argv[1]); +} + +int test_do_chown(int argc, char **argv) +{ + if (argc != 2) { + DBG(2, fprintf(outfp, "Number of args (%d) invalid for chown\n", + argc)); + return INVALID_ARGS; + } + last_type = SINT; + return sysio_chown(argv[0], argv[1]); +} + +int test_do_open(int argc, char **argv) +{ + char *name = argv[0]; + int flags = O_RDWR; + + if (argc > 1) + flags = get_obj(argv[1]); + + if (name[0] == '$') { + int index = get_obj(name); + + if (index < 0) { + DBG(2, fprintf(outfp, "Unable to find buffer at %s\n", + name)); + return INVALID_VAR; + } + + name = buflist[index]->buf; + } + + DBG(4, fprintf(outfp, "Opening file %s with flags %d\n", name, flags)); + if (argc == 2) + return sysio_open(name, flags); + else if (argc == 3) + return sysio_open3(name, flags, argv[2]); + else { + DBG(2, fprintf(outfp, "Invalid number of arguments (%d)\n", argc)); + return INVALID_ARGS; + } + last_type = UINT; + return SUCCESS; +} + +int test_do_close(int argc, char **argv) +{ + int fd; + char *name = argv[0]; + + if (argc != 1) { + DBG(2, fprintf(outfp, "Number of args (%d) invalid for close\n", + argc)); + return INVALID_ARGS; + } + + /* + * Assume that there is one arg and it + * is a variable name which maps to a file + * descriptor + */ + fd = get_obj(name); + if (fd < 0) { + DBG(2, fprintf(outfp, "Unable to map var %s to anything\n", name)); + return INVALID_VAR; + } + sysio_close(fd); + free_obj(name); + return SUCCESS; +} + +int test_do_dup(int argc, char **argv) +{ + int fd; + char *var_name = argv[0]; + + if (argc != 1) { + DBG(2, fprintf(outfp, "Number of args (%d) invalid for dup\n", + argc)); + return INVALID_ARGS; + } + + + fd = get_obj(var_name); + if (fd < 0) { + DBG(2, fprintf(outfp, "Unable to map var %s to any file\n", var_name)); + return INVALID_VAR; + } + + last_ret_val = dup(fd); + my_errno = errno; + last_type = SINT; + + return SUCCESS; +} + +int test_do_dup2(int argc, char **argv) +{ + int fd1, fd2; + char *var_name1 = argv[0]; + char *var_name2 = argv[1]; + + if (argc != 2) { + DBG(2, fprintf(outfp, "Number of args (%d) invalid for dup2\n", + argc)); + return INVALID_ARGS; + } + + fd1 = get_obj(var_name1); + if (fd1 < 0) { + DBG(2, fprintf(outfp, "Unable to map var %s to any file\n", var_name1)); + return INVALID_VAR; + } + + fd2 = get_obj(var_name2); + if (fd2 < 0) { + DBG(2, fprintf(outfp, "Unable to map var %s to any file\n", var_name2)); + return INVALID_VAR; + } + + last_ret_val = dup2(fd1, fd2); + my_errno = errno; + last_type = SINT; + + return SUCCESS; +} + +struct cmd_map fcntl_cmds[] = { + { "F_DUPFD", F_DUPFD, 3 }, + { "F_GETFD", F_GETFD, 2 }, + { "F_SETFD", F_SETFD, 3 }, + { "F_GETFL", F_GETFL, 2 }, + { "F_SETFL", F_SETFL, 3 }, + { "F_SETLK", F_SETLK, 3 }, + { "F_SETLKW", F_SETLKW, 3 }, + { "F_GETLK", F_GETLK, 3 }, +#if defined __USE_BSD || defined __USE_XOPEN2K + { "F_GETOWN", F_GETOWN, 2 }, + { "F_SETOWN", F_SETOWN, 3 }, +#endif +#ifdef __USE_GNU + { "F_GETSIG", F_GETSIG, 2 }, + { "F_SETSIG", F_SETSIG, 3 }, + { "F_SETLEASE", F_SETLEASE, 3}, + { "F_GETLEASE", F_GETLEASE, 2}, + { "F_NOTIFY", F_NOTIFY, 3} , +#endif + { NULL, -1, 0 } +}; + +struct cmd_map* get_cmd(char *cmd_name, int argc) +{ + int i =0; + + while (fcntl_cmds[i].cmd_name) { + if (!strcmp(fcntl_cmds[i].cmd_name, cmd_name)) { + if (fcntl_cmds[i].num_args == argc) + return &fcntl_cmds[i]; + else + return NULL; + } + i++; + } + return NULL; +} + +int test_do_fcntl(int argc, char **argv) +{ + + struct cmd_map *cmd; + int fd; + + /* + * get_cmd translates a symbolic command into + * into its numerical equivalent. It also + * verifies that the number of args is the + * correct number for the command. It returns + * NULL on failure + */ + cmd = get_cmd(argv[1], argc); + if (!cmd) { + DBG(2, fprintf(outfp, "Unable to get command %s\n", argv[1])); + return INVALID_ARGS; + } + + fd = get_obj(argv[0]); + if (fd < 0) { + DBG(2, fprintf(outfp, "Unable to map %s to file descriptor \n", argv[0])); + return INVALID_VAR; + } + + if (argc > 2) + last_ret_val = sysio_fcntl(fd, cmd, argv[2]); + else + last_ret_val = sysio_fcntl(fd, cmd, NULL); + DBG(4, fprintf(outfp, "Got return value of %d\n", (int)last_ret_val)); + my_errno = errno; + last_type = SINT; + + return SUCCESS; +} + +int test_do_fstat(int argc, char **argv) +{ + int fd, index; + void *buf; + + if (argc != 2) { + DBG(2, fprintf(outfp, "Invalid number of arguments (%d) for fstat\n", + argc)); + return INVALID_ARGS; + } + + fd = get_obj(argv[0]); + + if (fd < 0) { + DBG(2, fprintf(outfp, "Unable to find file assocated with %s\n", + argv[0])); + return INVALID_VAR; + } + + index = get_obj(argv[1]); + if (index < 0) { + DBG(2, fprintf(outfp, "Unable to find buffer assocated with %s\n", + argv[1])); + return INVALID_VAR; + } + + buf = buflist[index]->buf; + + last_ret_val = sysio_fstat(fd, buf); + my_errno = errno; + last_type = SINT; + + return SUCCESS; +} + +int test_do_lstat(int argc, char **argv) +{ + char *name = argv[0]; + int index; + void *buf; + + if (argc != 2) { + DBG(2, fprintf(outfp, "Invalid number of arguments (%d) for lstat\n", + argc)); + return INVALID_ARGS; + } + + index = get_obj(argv[1]); + if (index < 0) { + DBG(2, fprintf(outfp, "Unable to find buffer assocated with %s\n", + argv[1])); + return INVALID_VAR; + } + + buf = buflist[index]->buf; + last_type = SINT; + + return sysio_lstat(name, buf); +} + +int test_do_fsync(int argc, char **argv) +{ + int fd; + + if (argc != 1) { + DBG(2, fprintf(outfp, "Invalid number of arguments (%d) to fsync\n", argc)); + return INVALID_ARGS; + } + + + fd = get_obj(argv[0]); + + if (fd < 0) { + DBG(2, fprintf(outfp, "Unable to find file assocated with %s\n", + argv[0])); + return INVALID_VAR; + } + + last_ret_val = fsync(fd); + my_errno = errno; + last_type = SINT; + + return SUCCESS; +} + + +int test_do_fdatasync(int argc, char **argv) +{ + int fd; + + if (argc != 1) { + DBG(2, fprintf(outfp, "Invalid number of arguments (%d) to fdatasync\n", argc)); + return INVALID_ARGS; + } + + + fd = get_obj(argv[0]); + + if (fd < 0) { + DBG(2, fprintf(outfp, "Unable to find file assocated with %s\n", + argv[0])); + return INVALID_VAR; + } + + last_ret_val = fdatasync(fd); + my_errno = errno; + last_type = SINT; + + return SUCCESS; +} + + +int test_do_ftruncate(int argc, char **argv) +{ + int fd; + off_t length; + + if (argc != 2) { + DBG(2, fprintf(outfp, "Invalid number of arguments (%d) to ftruncate\n", argc)); + return INVALID_ARGS; + } + + + fd = get_obj(argv[0]); + + if (fd < 0) { + DBG(2, fprintf(outfp, "Unable to find file assocated with %s\n", + argv[0])); + return INVALID_VAR; + } + + length = (off_t)get_obj(argv[1]); + + DBG(3, fprintf(outfp, "Setting file %d to %d\n", fd, (int) length)); + + last_ret_val = ftruncate(fd, length); + my_errno = errno; + last_type = SINT; + + return SUCCESS; +} + +int test_do_getcwd(int argc, char **argv) +{ + char *buf; + int size, index; + + if (argc != 2) { + DBG(2, fprintf(outfp, "Invalid number of arguments (%d) to getcwd\n", argc)); + return INVALID_ARGS; + } + + index = get_obj(argv[0]); + if (index < 0) { + DBG(2, fprintf(outfp, "Unable to find buffer assocated with %s\n", + argv[1])); + return INVALID_VAR; + } + + buf = buflist[index]->buf; + + size = get_obj(argv[1]); + + DBG(4, fprintf(outfp, "Getting cwd with buffer size of %d\n", size)); + + last_ret_val = 0; + if (!getcwd(buf, size)) { + last_ret_val = -1; + if (errno == ERANGE) { + DBG(2, fprintf(outfp, "Need a bigger buffer!\n")); + } + } + + my_errno = errno; + + + DBG(3, fprintf(outfp, "cwd: %s\n", buf)); + last_type = SINT; + + return SUCCESS; +} + +int test_do_lseek(int argc, char **argv) +{ + int fd, whence; + off_t offset; + + + if (argc != 3) { + DBG(2, fprintf(outfp, "Invalid number of arguments (%d) to lseek\n", argc)); + return INVALID_ARGS; + } + + + fd = get_obj(argv[0]); + + if (fd < 0) { + DBG(2, fprintf(outfp, "Unable to find file assocated with %s\n", + argv[0])); + return INVALID_VAR; + } + + offset = (off_t)get_obj(argv[1]); + whence = get_obj(argv[2]); + + if (whence < 0 ) { + DBG(2, fprintf(outfp, "Not familiar with whence of %s\n", + argv[2])); + return INVALID_ARGS; + } + + last_ret_val = lseek(fd, offset, whence); + my_errno = errno; + last_type = SINT; + + return SUCCESS; +} + +int test_do_getdirentries(int argc, char **argv) +{ + int fd, nbytes; + int bufindex; + off_t basep; + char *buf; + struct var_mapping *base_map; + + if (argc != 4) { + DBG(2, fprintf(outfp, "Invalid number of arguments (%d) to getdirentries\n", argc)); + return INVALID_ARGS; + } + + fd = get_obj(argv[0]); + + if (fd < 0) { + DBG(2, fprintf(outfp, "Unable to find file assocated with %s\n", + argv[0])); + return INVALID_VAR; + } + + bufindex = get_obj(argv[1]); + + if (bufindex < 0) { + DBG(2, fprintf(outfp, "Unable to find buffer assocated with %s\n", + argv[1])); + return INVALID_VAR; + } + + buf = buflist[bufindex]->buf; + + nbytes = get_obj(argv[2]); + + if (nbytes < 0) { + DBG(2, fprintf(outfp, "I don't understand %s\n", + argv[2])); + return INVALID_ARGS; + } + + base_map = get_map(argv[3]); + if (!base_map) { + DBG(3, fprintf(outfp, "Resetting basep\n")); + /* + * Assume that this is the first getdirentries call + * and we need to setup the base pointer + */ + basep = 0; + } else + basep = base_map->obj; + + DBG(3, fprintf(outfp, "basep is (starting) %d\n", (int) basep)); + last_ret_val = sysio_getdirentries(fd, buf, nbytes, &basep); + if (base_map) + base_map->obj = basep; + else + store_result(argv[3]+1, basep); + DBG(3, fprintf(outfp, "basep is (ending) %d\n", (int) basep)); + my_errno = errno; + last_type = SINT; + + return SUCCESS; +} + +int test_do_mkdir(int argc, char **argv) +{ + if (argc !=2) { + DBG(2, fprintf(outfp, "Invalid number of arguments (%d) to mkdir\n", argc)); + return INVALID_ARGS; + } + + last_type = SINT; + return sysio_mkdir(argv[0], argv[1]); +} + +int test_do_creat(int argc, char **argv) +{ + if (argc !=2) { + DBG(2, fprintf(outfp, "Invalid number of arguments (%d) to creat\n", argc)); + return INVALID_ARGS; + } + + last_type = UINT; + return sysio_creat(argv[0], argv[1]); +} + +int test_do_stat(int argc, char **argv) +{ + int index; + void *buf; + char *str; + + if (argc != 2) { + fprintf(outfp, "Invalid number of arguments (%d) for stat\n", + argc); + return -1; + } + + + index = get_obj(argv[1]); + if (index < 0) { + fprintf(outfp, "Unable to find buffer assocated with %s\n", + argv[1]); + } + + buf = buflist[index]->buf; + last_type = SINT; + + str = get_str(argv[0]); + return sysio_stat(str, buf); +} + +int test_do_statvfs(int argc, char **argv) +{ + int index; + void *buf; + + if (argc != 2) { + fprintf(outfp, "Invalid number of arguments (%d) for statvfs\n", + argc); + return -1; + } + + + index = get_obj(argv[1]); + if (index < 0) { + fprintf(outfp, "Unable to find buffer assocated with %s\n", + argv[1]); + } + + buf = buflist[index]->buf; + last_type = SINT; + + return sysio_statvfs(argv[0], buf); +} + +int test_do_fstatvfs(int argc, char **argv) +{ + int index, fd; + void *buf; + + if (argc != 2) { + fprintf(outfp, "Invalid number of arguments (%d) for fstatvfs\n", + argc); + return -1; + } + + + fd = get_obj(argv[0]); + + if (fd < 0) { + fprintf(outfp, "Unable to find file assocated with %s\n", + argv[0]); + } + + + index = get_obj(argv[1]); + if (index < 0) { + fprintf(outfp, "Unable to find buffer assocated with %s\n", + argv[1]); + } + + buf = buflist[index]->buf; + last_type = SINT; + + return sysio_fstatvfs(fd, buf); +} + +int test_do_truncate(int argc, char **argv) +{ + off_t length; + + if (argc != 2) { + DBG(2, fprintf(outfp, "Invalid number of arguments (%d) to truncate\n", argc)); + return INVALID_ARGS; + } + + length = (off_t)get_obj(argv[1]); + + DBG(3, fprintf(outfp, "Setting file %s to %d\n", argv[0], (int) length)); + + last_ret_val = truncate(argv[0], length); + my_errno = errno; + last_type = SINT; + + return SUCCESS; +} + +int test_do_rmdir(int argc, char **argv) +{ + + if (argc != 1) { + DBG(2, fprintf(outfp, "Invalid number of arguments (%d) to rmdir\n", argc)); + return INVALID_ARGS; + } + + DBG(3, fprintf(outfp, "Removing dir %s\n", argv[0])); + + last_ret_val = rmdir(argv[0]); + my_errno = errno; + last_type = SINT; + + return SUCCESS; +} + +int test_do_symlink(int argc, char **argv) +{ + if (argc != 2) { + DBG(2, fprintf(outfp, "Invalid number of arguments (%d) to symlink\n", argc)); + return INVALID_ARGS; + } + + DBG(3, fprintf(outfp, "Linking %s to %s\n", argv[0], argv[1])); + + last_ret_val = symlink(argv[0], argv[1]); + if (last_ret_val) { + if (errno < 0) + errno = errno*-1; + my_perror("symlink"); + } + my_errno = errno; + last_type = SINT; + + return SUCCESS; +} + + +struct cmd_map ioctl_cmds[] = { +#if 0 + { "BLKROSET", BLKROSET, 3 }, + { "BLKROGET", BLKROGET, 3 }, + { "BLKRRPART", BLKRRPART, 3 }, + { "BLKGETSIZE", BLKGETSIZE, 3 }, + { "BLKRASET", BLKRASET, 3 }, + { "BLKRAGET", BLKRAGET, 3 }, + { "BLKSECTSET", BLKSECTSET, 3 }, + { "BLKSECTGET", BLKSECTGET, 3 }, + { "BLKSSZGET", BLKSSZGET, 3 }, + { "BLKGETLASTSECT", BLKGETLASTSECT, 3 }, + { "BLKSETLASTSECT", BLKSETLASTSECT, 3 }, + { "BLKBSZGET", BLKBSZGET, 3 }, + { "BLKBSZSET", BLKBSZSET, 3 }, + { "FIBMAP", FIBMAP, 3 }, + { "FIGETBSZ", FIGETBSZ, 3}, +#endif + { NULL, -1, 0 } +}; + +int get_ioctl_cmd(char *cmd) +{ + int i = 0; + + while (ioctl_cmds[i].cmd_name != NULL) { + if (strcmp(ioctl_cmds[i].cmd_name, cmd)) + i++; + else + return ioctl_cmds[i].cmd; + } + + return -1; +} + +int test_do_ioctl(int argc, char **argv) +{ + int fd, cmd; + + if (argc != 3) { + DBG(2, fprintf(outfp, "Invalid number of arguments (%d) to ioctl\n", argc)); + return INVALID_ARGS; + } + + + fd = get_obj(argv[0]); + if (fd < 0) { + DBG(2, fprintf(outfp, "Unable to find file %s\n", argv[0])); + return INVALID_VAR; + } + + cmd = get_ioctl_cmd(argv[1]); + if (cmd == -1) { + DBG(2, fprintf(outfp, "Do not understand command %s\n", argv[1])); + return INVALID_ARGS; + } + + DBG(3, fprintf(outfp, "Executing command %s\n", argv[1])); + + last_ret_val = ioctl(fd, cmd, argv[2]); + my_errno = errno; + if (last_ret_val) + my_perror("ioctl"); + last_type = SINT; + + return SUCCESS; +} + +int test_do_unlink(int argc, char **argv) +{ + if (argc != 1) { + DBG(2, fprintf(outfp, "Invalid number of arguments (%d) to unlink\n", argc)); + return INVALID_ARGS; + } + + DBG(4, fprintf(outfp, "Unlinking %s\n", argv[0])); + + last_ret_val = unlink(argv[0]); + my_errno = errno; + if (last_ret_val) + my_perror("unlink"); + last_type = SINT; + + return SUCCESS; +} + +int test_do_umask(int argc, char **argv) +{ + mode_t old_mask; + + if (argc != 1) { + DBG(2, fprintf(outfp, "Incorrect number of args (%d) for umask\n", argc)); + return INVALID_ARGS; + } + + last_ret_val = old_mask = sysio_umask(argv[0]); + my_errno = errno; + DBG(3, fprintf(outfp, "Previous umask was %o\n", old_mask)); + last_type = UINT; + + return SUCCESS; +} + +int test_do_iowait(int argc, char **argv) +{ + long err; + ioid_t ioid; + + if (argc != 1) { + DBG(2, fprintf(outfp, "Incorrect amount of args (%d) for iowait\n", argc)); + return INVALID_ARGS; + } + + err = get_obj(argv[0]); + if (err < 0) { + DBG(2, fprintf(outfp, "Cannot find ioid at %s\n", argv[0])); + return INVALID_VAR; + } + + ioid = (ioid_t)err; + + last_ret_val = iowait(ioid); + my_errno = errno; + if (last_ret_val < 0) { + my_perror("iowait"); + } + last_type = SINT; + + return SUCCESS; +} + +int test_do_iodone(int argc, char **argv) +{ + long err; + ioid_t ioid; + + if (argc != 1) { + DBG(2, fprintf(outfp, "Incorrect amount of args (%d) for iodone\n", argc)); + return INVALID_ARGS; + } + + err = get_obj(argv[0]); + if (err < 0) { + DBG(2, fprintf(outfp, "Cannot find ioid at %s\n", argv[0])); + return INVALID_VAR; + } + ioid = (ioid_t)err; + + last_ret_val = iowait(ioid); + if (last_ret_val < 0) { + my_perror("iodone"); + } + my_errno = errno; + last_type = SINT; + + return SUCCESS; + +} + +int test_do_ipread(int argc, char **argv) +{ + int fd, index, count, offset; + char *buf; + + if (argc != 4) { + DBG(2, fprintf(outfp, "Invalid number of arguments (%d) to ipread\n", argc)); + return INVALID_ARGS; + } + + fd = get_obj(argv[0]); + if (fd < 0) { + DBG(2, fprintf(outfp, "Unable to find file at %s\n", argv[0])); + return INVALID_VAR; + } + + index = get_obj(argv[1]); + if (index < 0) { + DBG(2, fprintf(outfp, "Unable to find buffer at %s\n", argv[1])); + return INVALID_VAR; + } + + buf = buflist[index]->buf; + + count = get_obj(argv[2]); + if (count < 0) { + DBG(2, fprintf(outfp, "Do not understand count %s\n", argv[2])); + return INVALID_ARGS; + } + + offset = get_obj(argv[3]); + if (offset < 0) { + DBG(2, fprintf(outfp, "Unable to understand offset of %s\n", argv[3])); + return INVALID_ARGS; + } + + last_ret_val = (long)ipread(fd, buf, count, offset); + if (last_ret_val < 0) { + my_perror("ipread"); + } + my_errno = errno; + last_type = SINT; + + return SUCCESS; +} + +int test_do_iread(int argc, char **argv) +{ + int fd, index, count; + char *buf; + + if (argc != 3) { + DBG(2, fprintf(outfp, "Invalid number of arguments (%d) to iread\n", argc)); + return INVALID_ARGS; + } + + fd = get_obj(argv[0]); + if (fd < 0) { + DBG(2, fprintf(outfp, "Unable to find file at %s\n", argv[0])); + return INVALID_VAR; + } + + index = get_obj(argv[1]); + if (index < 0) { + DBG(2, fprintf(outfp, "Unable to find buffer at %s\n", argv[1])); + return INVALID_VAR; + } + + buf = buflist[index]->buf; + + count = get_obj(argv[2]); + if (count < 0) { + DBG(2, fprintf(outfp, "Do not understand count %s\n", argv[2])); + return INVALID_ARGS; + } + + last_ret_val = (long) iread(fd, buf, count); + if (last_ret_val < 0) { + my_perror("iread"); + } + my_errno = errno; + last_type = SINT; + + return SUCCESS; +} + + +int test_do_ipreadv(int argc, char **argv) +{ + int fd, count, index; + off_t offset; + char *buf; + struct iovec *iov; + + if (argc != 4) { + DBG(2, fprintf(outfp, "Invalid number of arguments (%d) to ipreadv\n", argc)); + return INVALID_ARGS; + } + + fd = get_obj(argv[0]); + + if (fd < 0) { + DBG(2, fprintf(outfp, "Unable to find file described by %s\n", argv[0])); + return INVALID_VAR; + } + + index = get_obj(argv[1]); + + if (index < 0) { + DBG(2, fprintf(outfp, "Unable to find buffer described by %s\n", argv[1])); + return INVALID_VAR; + } + + buf = buflist[index]->buf; + + iov = (struct iovec *)buf; + count = get_obj(argv[2]); + + if (count < 0) { + DBG(2, fprintf(outfp, "Unable to understand %s\n", argv[2])); + return INVALID_ARGS; + } + + offset = get_obj(argv[3]); + if (offset < 0) { + DBG(2, fprintf(outfp, "Unable to understand offset value %s\n", argv[3])); + return INVALID_ARGS; + } + + DBG(3, fprintf(outfp, "ipreadv(fd: %d vector:{iov_base: %p iov_len %d} count: %d offset: %d\n", + fd, iov->iov_base, (int)iov->iov_len, count, (int) offset)); + + last_ret_val = (long) ipreadv(fd, iov, count, offset); + if (last_ret_val < 0) + my_perror("ipreadv"); + my_errno = errno; + last_type = SINT; + + return SUCCESS; +} + + +int test_do_preadv(int argc, char **argv) +{ + int fd, count, index; + off_t offset; + char *buf; + struct iovec *iov; + + if (argc != 4) { + DBG(2, fprintf(outfp, "Invalid number of arguments (%d) to preadv\n", argc)); + return INVALID_ARGS; + } + + fd = get_obj(argv[0]); + + if (fd < 0) { + DBG(2, fprintf(outfp, "Unable to find file described by %s\n", argv[0])); + return INVALID_VAR; + } + + index = get_obj(argv[1]); + + if (index < 0) { + DBG(2, fprintf(outfp, "Unable to find buffer described by %s\n", argv[1])); + return INVALID_VAR; + } + + buf = buflist[index]->buf; + + iov = (struct iovec *)buf; + count = get_obj(argv[2]); + + if (count < 0) { + DBG(2, fprintf(outfp, "Unable to understand %s\n", argv[2])); + return INVALID_ARGS; + } + + offset = get_obj(argv[3]); + if (offset < 0) { + DBG(2, fprintf(outfp, "Unable to understand offset value %s\n", argv[3])); + return INVALID_ARGS; + } + + DBG(3, fprintf(outfp, "preadv(fd: %d vector:{iov_base: %p iov_len %d} count: %d offset: %d\n", + fd, iov->iov_base, (int) iov->iov_len, count, (int) offset)); + + last_ret_val = preadv(fd, iov, count, offset); + my_errno = errno; + if (last_ret_val < 0) + my_perror("preadv"); + last_type = SINT; + + return SUCCESS; +} + + +int test_do_pread(int argc, char **argv) +{ + int fd, count, index, numbytes, offset; + char *buf; + + if (argc != 4) { + DBG(2, fprintf(outfp, "Invalid number of arguments (%d) to pread\n", argc)); + return INVALID_ARGS; + } + + + fd = get_obj(argv[0]); + + if (fd < 0) { + DBG(2, fprintf(outfp, "Unable to find file assocated with %s\n", + argv[0])); + return INVALID_VAR; + } + + index = get_obj(argv[1]); + + if (index < 0) { + DBG(2, fprintf(outfp, "Unable to find buffer assocated with %s\n", + argv[1])); + return INVALID_VAR; + } + + buf = buflist[index]->buf; + + count = get_obj(argv[2]); + if (count < 0) { + DBG(2, fprintf(outfp, "Unable to understand count of %s\n", argv[1])); + return INVALID_ARGS; + } + + offset = get_obj(argv[3]); + if (count < 0) { + DBG(2, fprintf(outfp, "Unable to understand offset of %s\n", argv[2])); + return INVALID_ARGS; + } + + + last_ret_val = numbytes = (int) pread(fd, buf, count, offset); + my_errno = errno; + DBG(4, fprintf(outfp, "Read %d bytes out of %d starting at offset %x\n", + numbytes, count, offset)); + DBG(3, fprintf(outfp, "Got %s\n", buf)); + last_type = SINT; + + return SUCCESS; +} + + +int test_do_ireadv(int argc, char **argv) +{ + int fd, count, index; + char *buf; + struct iovec *iov; + + if (argc != 3) { + DBG(2, fprintf(outfp, "Invalid number of arguments (%d) to ireadv\n", argc)); + return INVALID_ARGS; + } + + fd = get_obj(argv[0]); + + if (fd < 0) { + DBG(2, fprintf(outfp, "Unable to find file described by %s\n", argv[0])); + return INVALID_VAR; + } + + index = get_obj(argv[1]); + + if (index < 0) { + DBG(2, fprintf(outfp, "Unable to find buffer described by %s\n", argv[1])); + return INVALID_VAR; + } + + buf = buflist[index]->buf; + + iov = (struct iovec *)buf; + count = get_obj(argv[2]); + + if (count < 0) { + DBG(2, fprintf(outfp, "Unable to understand %s\n", argv[2])); + return INVALID_ARGS; + } + + DBG(3, fprintf(outfp, "ireadv (fd: %d, vector:{ iov_base: %p iov_len %d }, count: %d\n", + fd, iov->iov_base, (int)iov->iov_len, count)); + + last_ret_val = (long) ireadv(fd, iov, count); + if (last_ret_val < 0) + my_perror("ireadv"); + my_errno = errno; + last_type = SINT; + + return SUCCESS; +} + +int test_do_readv(int argc, char **argv) +{ + int fd, count, index; + char *buf; + struct iovec *iov; + + if (argc != 3) { + DBG(2, fprintf(outfp, "Invalid number of arguments (%d) to readv\n", argc)); + return INVALID_ARGS; + } + + fd = get_obj(argv[0]); + + if (fd < 0) { + DBG(2, fprintf(outfp, "Unable to find file described by %s\n", argv[0])); + return INVALID_VAR; + } + + index = get_obj(argv[1]); + + if (index < 0) { + DBG(2, fprintf(outfp, "Unable to find buffer described by %s\n", argv[1])); + return INVALID_VAR; + } + + buf = buflist[index]->buf; + + iov = (struct iovec *)buf; + count = get_obj(argv[2]); + + if (count < 0) { + DBG(2, fprintf(outfp, "Unable to understand %s\n", argv[2])); + return INVALID_ARGS; + } + + DBG(3, fprintf(outfp, "ireadv (fd: %d, vector:{ iov_base: %p iov_len %d }, count: %d\n", + fd, iov->iov_base, (int)iov->iov_len, count)); + + last_ret_val = readv(fd, iov, count); + if (last_ret_val < 0) + my_perror("readv"); + my_errno = errno; + last_type = SINT; + + return SUCCESS; +} + +int test_do_read(int argc, char **argv) +{ + int fd, count, index, numbytes=0; + char *buf; + + if (argc < 3) { + DBG(2, fprintf(outfp, "Invalid number of arguments (%d) to read\n", argc)); + return INVALID_ARGS; + } + + + fd = get_obj(argv[0]); + + if (fd < 0) { + DBG(2, fprintf(outfp, "Unable to find file assocated with %s\n", + argv[0])); + return INVALID_VAR; + } + + index = get_obj(argv[1]); + + + if (index < 0) { + DBG(2, fprintf(outfp, "Unable to find buffer assocated with %s\n", + argv[1])); + return INVALID_VAR; + } + + buf = buflist[index]->buf; + + count = get_obj(argv[2]); + + if ( (argc == 4) && (!strcmp(argv[3], "delay")) ){ + int i; + /* Wait a little while for input */ + for (i=0; i < count; i++) { + sleep(0.005); + numbytes += (int) read(fd, buf, 1); + last_ret_val = numbytes; + + } + } else { + last_ret_val = numbytes = (int) read(fd, buf, count); + } + my_errno = errno; + + DBG(3, fprintf(outfp, "Read %d bytes out of %d\n", numbytes, count)); + DBG(3, fprintf(outfp, "Got %s\n", buf)); + last_type = SINT; + + return SUCCESS; +} + +int test_do_ipwritev(int argc, char **argv) +{ + int fd, count, index, offset; + char *buf; + struct iovec *iov; + + if (argc != 4) { + DBG(2, fprintf(outfp, "Invalid number of arguments (%d) to ipwritev\n", argc)); + return INVALID_ARGS; + } + + fd = get_obj(argv[0]); + + if (fd < 0) { + DBG(2, fprintf(outfp, "Unable to find file described by %s\n", argv[0])); + return INVALID_VAR; + } + + index = get_obj(argv[1]); + + if (index < 0) { + DBG(2, fprintf(outfp, "Unable to find buffer described by %s\n", argv[1])); + return INVALID_VAR; + } + + buf = buflist[index]->buf; + + iov = (struct iovec *)buf; + + count = get_obj(argv[2]); + if (count < 0) { + DBG(2, fprintf(outfp, "Unable to understand count %s\n", argv[2])); + return INVALID_ARGS; + } + + offset = get_obj(argv[3]); + if (offset < 0) { + DBG(2, fprintf(outfp, "Unable to understand offset %s\n", argv[3])); + return INVALID_ARGS; + } + + DBG(3, fprintf(outfp, + "ipwritev(fd: %d, vector: { iov_base: %p iov_len %d }, count: %d, offset: %d\n", + fd, iov->iov_base, (int)iov->iov_len, count, offset)); + + last_ret_val = (long) ipwritev(fd, iov, count, offset); + my_errno = errno; + if (last_ret_val < 0) + my_perror("ipwritev"); + last_type = SINT; + + return SUCCESS; +} + +int test_do_ipwrite(int argc, char **argv) +{ + int fd, count, index, offset; + char *buf; + + if (argc != 4) { + DBG(2, fprintf(outfp, "Invalid number of arguments (%d) to ipwrite\n", argc)); + return INVALID_ARGS; + } + + fd = get_obj(argv[0]); + + if (fd < 0) { + DBG(2, fprintf(outfp, "Unable to find file described by %s\n", argv[0])); + return INVALID_VAR; + } + + index = get_obj(argv[1]); + + if (index < 0) { + DBG(2, fprintf(outfp, "Unable to find buffer described by %s\n", argv[1])); + return INVALID_VAR; + } + + buf = buflist[index]->buf; + + count = get_obj(argv[2]); + if (count < 0) { + DBG(2, fprintf(outfp, "Unable to understand count %s\n", argv[2])); + return INVALID_ARGS; + } + + offset = get_obj(argv[3]); + if (offset < 0) { + DBG(2, fprintf(outfp, "Unable to understand offset %s\n", argv[3])); + return INVALID_ARGS; + } + + last_ret_val = (long) ipwrite(fd, buf, count, offset); + if (last_ret_val < 0) + my_perror("ipwrite"); + my_errno = errno; + last_type = SINT; + + return SUCCESS; +} + +int test_do_pwritev(int argc, char **argv) +{ + int fd, count, index, offset; + char *buf; + struct iovec *iov; + + if (argc != 4) { + DBG(2, fprintf(outfp, "Invalid number of arguments (%d) to pwritev\n", argc)); + return INVALID_ARGS; + } + + fd = get_obj(argv[0]); + + if (fd < 0) { + DBG(2, fprintf(outfp, "Unable to find file described by %s\n", argv[0])); + return INVALID_VAR; + } + + index = get_obj(argv[1]); + + if (index < 0) { + DBG(2, fprintf(outfp, "Unable to find buffer described by %s\n", argv[1])); + return INVALID_VAR; + } + + buf = buflist[index]->buf; + + iov = (struct iovec *)buf; + + count = get_obj(argv[2]); + if (count < 0) { + DBG(2, fprintf(outfp, "Unable to understand count %s\n", argv[2])); + return INVALID_ARGS; + } + + offset = get_obj(argv[3]); + if (offset < 0) { + DBG(2, fprintf(outfp, "Unable to understand offset %s\n", argv[3])); + return INVALID_ARGS; + } + + + DBG(3, fprintf(outfp, + "pwritev(fd: %d, vector: { iov_base: %p iov_len %d }, count: %d, offset: %d\n", + fd, iov->iov_base, (int)iov->iov_len, count, offset)); + + last_ret_val = (long) pwritev(fd, iov, count, offset); + if (last_ret_val < 0) + my_perror("ipwritev"); + my_errno = errno; + last_type = SINT; + + return SUCCESS; +} + +int test_do_pwrite(int argc, char **argv) +{ + int fd, count, index, offset; + char *buf; + + if (argc != 4) { + DBG(2, fprintf(outfp, "Invalid number of arguments (%d) to pwrite\n", argc)); + return INVALID_ARGS; + } + + fd = get_obj(argv[0]); + + if (fd < 0) { + DBG(2, fprintf(outfp, "Unable to find file described by %s\n", argv[0])); + return INVALID_VAR; + } + + index = get_obj(argv[1]); + + if (index < 0) { + DBG(2, fprintf(outfp, "Unable to find buffer described by %s\n", argv[1])); + return INVALID_VAR; + } + + buf = buflist[index]->buf; + + count = get_obj(argv[2]); + if (count < 0) { + DBG(2, fprintf(outfp, "Unable to understand count %s\n", argv[2])); + return INVALID_ARGS; + } + + offset = get_obj(argv[3]); + if (offset < 0) { + DBG(2, fprintf(outfp, "Unable to understand offset %s\n", argv[3])); + return INVALID_ARGS; + } + + last_ret_val = pwrite(fd, buf, count, offset); + my_errno = errno; + if (last_ret_val < 0) + my_perror("pwrite"); + last_type = SINT; + + return SUCCESS; +} + + +int test_do_iwritev(int argc, char **argv) +{ + int fd, count, index; + char *buf; + struct iovec *iov; + + if (argc != 3) { + DBG(2, fprintf(outfp, "Invalid number of arguments (%d) to iwritev\n", argc)); + return INVALID_ARGS; + } + + fd = get_obj(argv[0]); + + if (fd < 0) { + DBG(2, fprintf(outfp, "Unable to find file described by %s\n", argv[0])); + return INVALID_VAR; + } + + index = get_obj(argv[1]); + + if (index < 0) { + DBG(2, fprintf(outfp, "Unable to find buffer described by %s\n", argv[1])); + return INVALID_VAR; + } + + buf = buflist[index]->buf; + + iov = (struct iovec *)buf; + + count = get_obj(argv[2]); + if (count < 0) { + DBG(2, fprintf(outfp, "Unable to understand count %s\n", argv[2])); + return INVALID_ARGS; + } + + DBG(3, fprintf(outfp, "iwritev(fd: %d, vector: { iov_base: %p iov_len %d }, count: %d\n", + fd, iov->iov_base, (int)iov->iov_len, count)); + + last_ret_val = (long) iwritev(fd, iov, count); + my_errno = errno; + if (last_ret_val < 0) + my_perror("iwritev"); + last_type = SINT; + + return SUCCESS; +} + +int test_do_iwrite(int argc, char **argv) +{ + int fd, count, index; + char *buf; + + if (argc != 3) { + DBG(2, fprintf(outfp, "Invalid number of arguments (%d) to iwrite\n", argc)); + return INVALID_ARGS; + } + + fd = get_obj(argv[0]); + + if (fd < 0) { + DBG(2, fprintf(outfp, "Unable to find file described by %s\n", argv[0])); + return INVALID_VAR; + } + + index = get_obj(argv[1]); + + if (index < 0) { + DBG(2, fprintf(outfp, "Unable to find buffer described by %s\n", argv[1])); + return INVALID_VAR; + } + + buf = buflist[index]->buf; + + count = get_obj(argv[2]); + if (count < 0) { + DBG(2, fprintf(outfp, "Unable to understand count %s\n", argv[2])); + return INVALID_ARGS; + } + + last_ret_val = (long) iwrite(fd, buf, count); + my_errno = errno; + if (last_ret_val < 0) + my_perror("iwrite"); + last_type = SINT; + + return SUCCESS; +} + + +int test_do_write(int argc, char **argv) +{ + int fd, count, index, err; + char *buf; + + if (argc != 3) { + DBG(2, fprintf(outfp, "Invalid number of arguments (%d) to write\n", argc)); + return INVALID_ARGS; + } + + fd = get_obj(argv[0]); + + if (fd < 0) { + DBG(2, fprintf(outfp, "Unable to find file described by %s\n", argv[0])); + return INVALID_VAR; + } + + index = get_obj(argv[1]); + + if (index < 0) { + DBG(2, fprintf(outfp, "Unable to find buffer described by %s\n", argv[1])); + return INVALID_VAR; + } + + buf = buflist[index]->buf; + + count = get_obj(argv[2]); + if (count < 0) { + DBG(2, fprintf(outfp, "Unable to understand count %s\n", argv[2])); + return INVALID_ARGS; + } + + DBG(4, fprintf(outfp, "Writing out %d bytes (%s) using fd of %x\n", + count, buf, fd)); + err = write(fd, buf, count); + if (err < 0) + my_perror("write"); + + last_ret_val = err; + my_errno = errno; + last_type = SINT; + + return SUCCESS; +} + + +int test_do_writev(int argc, char **argv) +{ + int fd, count, index; + char *buf; + struct iovec *iov; + + if (argc != 3) { + DBG(2, fprintf(outfp, "Invalid number of arguments (%d) to writev\n", argc)); + return INVALID_ARGS; + } + + fd = get_obj(argv[0]); + + if (fd < 0) { + DBG(2, fprintf(outfp, "Unable to find file described by %s\n", argv[0])); + return INVALID_ARGS; + } + + index = get_obj(argv[1]); + + if (index < 0) { + DBG(2, fprintf(outfp, "Unable to find buffer described by %s\n", argv[1])); + return INVALID_VAR; + } + + buf = buflist[index]->buf; + + iov = (struct iovec *)buf; + count = get_obj(argv[2]); + + if (count < 0) { + DBG(2, fprintf(outfp, "Unable to understand %s\n", argv[2])); + return INVALID_ARGS; + } + + DBG(3, fprintf(outfp, "writev(fd: %d, vector: { iov_base: %p iov_len %d }, count: %d\n", + fd, iov->iov_base, (int)iov->iov_len, count)); + + last_ret_val = writev(fd, iov, count); + if (last_ret_val < 0) + my_perror("writev"); + my_errno = errno; + last_type = SINT; + + return SUCCESS; +} + +int test_do_mknod(int argc, char **argv) +{ + int dev; + + if (argc != 3) { + DBG(2, fprintf(outfp, "Invalid number of args (%d) for mknod\n", argc)); + return INVALID_ARGS; + } + + dev = get_obj(argv[2]); + if (dev < 0) { + DBG(2, fprintf(outfp, "Unable to understand %s\n", argv[2])); + return INVALID_ARGS; + } + last_type = SINT; + + + return sysio_mknod(argv[0], argv[1], (dev_t) dev); +} + +int test_do_umount(int argc, char **argv) +{ + int err; + + if (argc != 1) { + DBG(2, fprintf(outfp, "Invalid number (%d) of args for umount\n", argc)); + return INVALID_ARGS; + } + + err = umount(argv[0]); + if (err) + my_perror("umount"); + + my_errno = errno; + last_ret_val = err; + last_type = SINT; + + return SUCCESS; +} + +int test_do_init_iovec(int argc, char **argv) +{ + int iov_index, buf_index; + int offset, len, pos; + struct iovec *iov_ptr; + char *base_ptr; + + if (argc != 5) { + DBG(2, fprintf(outfp, "Need buffer, offset, len, array pos, and iov pointer\n")); + return INVALID_ARGS; + } + + if ((buf_index = get_obj(argv[0])) < 0) { + DBG(2, fprintf(outfp, "Unable to find object %s\n", argv[0])); + return INVALID_VAR; + } + base_ptr = buflist[buf_index]->buf; + + if ((offset = get_obj(argv[1])) < 0) { + DBG(2, fprintf(outfp, "Cannot understand offset of %s\n", argv[1])); + return INVALID_VAR; + } + + if ((len = get_obj(argv[2])) < 0) { + DBG(2, fprintf(outfp, "Cannot understand len of %s\n", argv[2])); + return INVALID_VAR; + } + + if ((pos = get_obj(argv[3])) < 0) { + DBG(2, fprintf(outfp, "Cannot understand array pos of %s\n", argv[3])); + return INVALID_VAR; + } + + if ((iov_index = get_obj(argv[4])) < 0) { + DBG(2, fprintf(outfp, "Unable to find object %s\n", argv[4])); + return INVALID_VAR; + } + iov_ptr = (struct iovec *)(buflist[iov_index]->buf); + + iov_ptr[pos].iov_len = len; + iov_ptr[pos].iov_base = (void *)(base_ptr + offset); + + DBG(3, fprintf(outfp, "iov_ptr.len is %d and base is %p\n", + (int)iov_ptr[pos].iov_len, iov_ptr[pos].iov_base)); + my_errno = errno; + last_type = PTR; + + return SUCCESS; +} + + +int test_do_init_xtvec(int argc, char **argv) +{ + int xtv_index; + int offset, len, pos; + struct xtvec *xtv_ptr; + + if (argc != 4) { + DBG(2, fprintf(outfp, "Need offset, len, array pos, and xtv pointer\n")); + return INVALID_ARGS; + } + + if ((offset = get_obj(argv[0])) < 0) { + DBG(2, fprintf(outfp, "Cannot understand offset of %s\n", argv[0])); + return INVALID_VAR; + } + + if ((len = get_obj(argv[1])) < 0) { + DBG(2, fprintf(outfp, "Cannot understand len of %s\n", argv[1])); + return INVALID_VAR; + } + + if ((pos = get_obj(argv[2])) < 0) { + DBG(2, fprintf(outfp, "Cannot understand array pos of %s\n", argv[2])); + return INVALID_VAR; + } + + if ((xtv_index = get_obj(argv[3])) < 0) { + DBG(2, fprintf(outfp, "Unable to find object %s\n", argv[3])); + return INVALID_VAR; + } + xtv_ptr = (struct xtvec *)(buflist[xtv_index]->buf); + + xtv_ptr[pos].xtv_len = len; + xtv_ptr[pos].xtv_off = offset; + + DBG(3, fprintf(outfp, "xtv_ptr.len is %d and offset is %d\n", + (int)xtv_ptr[pos].xtv_len, (int)xtv_ptr[pos].xtv_off)); + + my_errno = errno; + last_type = PTR; + + return SUCCESS; +} + +int test_do_writex(int argc, char **argv) +{ + int fd, iov_count, xtv_count,index; + char *buf; + struct iovec *iov; + struct xtvec *xtv; + + if (argc != 5) { + DBG(2, fprintf(outfp, "Invalid number of arguments (%d) to writex\n", argc)); + return INVALID_ARGS; + } + + fd = get_obj(argv[0]); + + if (fd < 0) { + DBG(2, fprintf(outfp, "Unable to find file described by %s\n", argv[0])); + return INVALID_ARGS; + } + + index = get_obj(argv[1]); + + if (index < 0) { + DBG(2, fprintf(outfp, "Unable to find buffer described by %s\n", argv[1])); + return INVALID_VAR; + } + + buf = buflist[index]->buf; + + iov = (struct iovec *)buf; + iov_count = get_obj(argv[2]); + + if (iov_count < 0) { + DBG(2, fprintf(outfp, "Unable to understand %s\n", argv[2])); + return INVALID_ARGS; + } + + index = get_obj(argv[3]); + + if (index < 0) { + DBG(2, fprintf(outfp, "Unable to find xtvs described by %s\n", argv[3])); + return INVALID_VAR; + } + + buf = buflist[index]->buf; + + xtv = (struct xtvec *)buf; + xtv_count = get_obj(argv[4]); + + if (xtv_count < 0) { + DBG(2, fprintf(outfp, "Unable to understand %s\n", argv[4])); + return INVALID_ARGS; + } + + DBG(3, fprintf(outfp, "writex(fd: %d, iov: %p iov_cnt: %d, xtv: %p, xtv_cnt: %d\n", + fd, (void *)iov, iov_count, (void *)xtv, xtv_count)); + + last_ret_val = writex(fd, iov, iov_count, xtv, xtv_count); + if (last_ret_val < 0) + my_perror("writex"); + my_errno = errno; + last_type = SINT; + + return SUCCESS; +} + + +int test_do_iwritex(int argc, char **argv) +{ + int fd, iov_count, xtv_count,index; + char *buf; + struct iovec *iov; + struct xtvec *xtv; + + if (argc != 5) { + DBG(2, fprintf(outfp, "Invalid number of arguments (%d) to iwritex\n", argc)); + return INVALID_ARGS; + } + + fd = get_obj(argv[0]); + + if (fd < 0) { + DBG(2, fprintf(outfp, "Unable to find file described by %s\n", argv[0])); + return INVALID_ARGS; + } + + index = get_obj(argv[1]); + + if (index < 0) { + DBG(2, fprintf(outfp, "Unable to find buffer described by %s\n", argv[1])); + return INVALID_VAR; + } + + buf = buflist[index]->buf; + + iov = (struct iovec *)buf; + iov_count = get_obj(argv[2]); + + if (iov_count < 0) { + DBG(2, fprintf(outfp, "Unable to understand %s\n", argv[2])); + return INVALID_ARGS; + } + + index = get_obj(argv[3]); + + if (index < 0) { + DBG(2, fprintf(outfp, "Unable to find xtvs described by %s\n", argv[3])); + return INVALID_VAR; + } + + buf = buflist[index]->buf; + + xtv = (struct xtvec *)buf; + xtv_count = get_obj(argv[4]); + + if (xtv_count < 0) { + DBG(2, fprintf(outfp, "Unable to understand %s\n", argv[4])); + return INVALID_ARGS; + } + + DBG(3, fprintf(outfp, "iwritex(fd: %d, iov: %p iov_cnt: %d, xtv: %p, xtv_cnt: %d\n", + fd, (void *)iov, iov_count, (void *)xtv, xtv_count)); + + last_ret_val = (long) iwritex(fd, iov, iov_count, xtv, xtv_count); + if (last_ret_val < 0) + my_perror("iwritex"); + my_errno = errno; + last_type = SINT; + + return SUCCESS; +} + + +int test_do_readx(int argc, char **argv) +{ + int fd, iov_count, xtv_count,index; + char *buf; + struct iovec *iov; + struct xtvec *xtv; + + if (argc != 5) { + DBG(2, fprintf(outfp, "Invalid number of arguments (%d) to readx\n", argc)); + return INVALID_ARGS; + } + + fd = get_obj(argv[0]); + + if (fd < 0) { + DBG(2, fprintf(outfp, "Unable to find file described by %s\n", argv[0])); + return INVALID_ARGS; + } + + index = get_obj(argv[1]); + + if (index < 0) { + DBG(2, fprintf(outfp, "Unable to find buffer described by %s\n", argv[1])); + return INVALID_VAR; + } + + buf = buflist[index]->buf; + + iov = (struct iovec *)buf; + iov_count = get_obj(argv[2]); + + if (iov_count < 0) { + DBG(2, fprintf(outfp, "Unable to understand %s\n", argv[2])); + return INVALID_ARGS; + } + + index = get_obj(argv[3]); + + if (index < 0) { + DBG(2, fprintf(outfp, "Unable to find xtvs described by %s\n", argv[3])); + return INVALID_VAR; + } + + buf = buflist[index]->buf; + + xtv = (struct xtvec *)buf; + xtv_count = get_obj(argv[4]); + + if (xtv_count < 0) { + DBG(2, fprintf(outfp, "Unable to understand %s\n", argv[4])); + return INVALID_ARGS; + } + + DBG(3, fprintf(outfp, "readx(fd: %d, iov: %p iov_cnt: %d, xtv: %p, xtv_cnt: %d\n", + fd, (void *)iov, iov_count, (void *)xtv, xtv_count)); + + last_ret_val = readx(fd, iov, iov_count, xtv, xtv_count); + if (last_ret_val < 0) + my_perror("readx"); + my_errno = errno; + last_type = SINT; + + return SUCCESS; +} + + +int test_do_ireadx(int argc, char **argv) +{ + int fd, iov_count, xtv_count,index; + char *buf; + struct iovec *iov; + struct xtvec *xtv; + + if (argc != 5) { + DBG(2, fprintf(outfp, "Invalid number of arguments (%d) to ireadx\n", argc)); + return INVALID_ARGS; + } + + fd = get_obj(argv[0]); + + if (fd < 0) { + DBG(2, fprintf(outfp, "Unable to find file described by %s\n", argv[0])); + return INVALID_ARGS; + } + + index = get_obj(argv[1]); + + if (index < 0) { + DBG(2, fprintf(outfp, "Unable to find buffer described by %s\n", argv[1])); + return INVALID_VAR; + } + + buf = buflist[index]->buf; + + iov = (struct iovec *)buf; + iov_count = get_obj(argv[2]); + + if (iov_count < 0) { + DBG(2, fprintf(outfp, "Unable to understand %s\n", argv[2])); + return INVALID_ARGS; + } + + index = get_obj(argv[3]); + + if (index < 0) { + DBG(2, fprintf(outfp, "Unable to find xtvs described by %s\n", argv[3])); + return INVALID_VAR; + } + + buf = buflist[index]->buf; + + xtv = (struct xtvec *)buf; + xtv_count = get_obj(argv[4]); + + if (xtv_count < 0) { + DBG(2, fprintf(outfp, "Unable to understand %s\n", argv[4])); + return INVALID_ARGS; + } + + DBG(3, fprintf(outfp, "ireadx(fd: %d, iov: %p iov_cnt: %d, xtv: %p, xtv_cnt: %d\n", + fd, (void *)iov, iov_count, (void *)xtv, xtv_count)); + + last_ret_val = (long) ireadx(fd, iov, iov_count, xtv, xtv_count); + if (last_ret_val < 0) + my_perror("ireadx"); + my_errno = errno; + last_type = SINT; + + return SUCCESS; +} + + +int do_checkbuf(int argc, char **argv) +{ + int size, val, index, i, offset; + int *ref_buf, *buf; + + if (argc != 4) { + DBG(2, fprintf(outfp, "Need buffer, val, and offset for checkbuf\n")); + return INVALID_ARGS; + } + + index = get_obj(argv[0]); + + if (index < 0) { + DBG(2, fprintf(outfp, "Unable to find buf described by %s\n", argv[0])); + return INVALID_VAR; + } + + buf = (int *)buflist[index]->buf; + + + size = get_obj(argv[1]); + + if (size < 0) { + DBG(2, fprintf(outfp, "Unable to understand %s\n", argv[1])); + return INVALID_ARGS; + } + + val = get_obj(argv[2]); + + if (val < 0) { + DBG(2, fprintf(outfp, "Unable to understand %s\n", argv[2])); + return INVALID_ARGS; + } + + + offset = get_obj(argv[3]); + + if (offset < 0) { + DBG(2, fprintf(outfp, "Unable to understand %s\n", argv[3])); + return INVALID_ARGS; + } + + + ref_buf = (int *)malloc(size); + memset((void *)ref_buf, val, size); + + last_ret_val =0; + buf = (int *)((char *)buf + offset); + for (i=0; (unsigned)i < size/sizeof(int); i++) { + if (buf[i] != ref_buf[i]) { + DBG(2, fprintf(stderr, "At pos %d I found a 0x%08x instead of 0x%08x\n", + i, buf[i], ref_buf[i])); + fprintf(stderr, "At pos %d I found a 0x%08x instead of 0x%08x (val was %d)\n", + i, buf[i], ref_buf[i], val); + last_ret_val = 1; + break; + } + } + + my_errno = errno; + last_type = SINT; + + return SUCCESS; +} diff --git a/libsysio/tests/sysio_tests.c b/libsysio/tests/sysio_tests.c new file mode 100644 index 0000000..8f2f301 --- /dev/null +++ b/libsysio/tests/sysio_tests.c @@ -0,0 +1,859 @@ +#define _BSD_SOURCE + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 + * + */ +int sysio_chmod(char *mode_arg, const char *path) +{ + int err; + mode_t mode; + struct stat st; + + /* Get the current mode */ + err = stat(path, &st); + + /* Is the new mode symbolic? */ + if (isalpha(mode_arg[0])) { + /* Could be specifying defines */ + if (mode_arg[0] == 'S') + mode = get_mode(mode_arg, DEFINED, st.st_mode); + else + mode = get_mode(mode_arg, SYMBOLIC, st.st_mode); + } else + mode = get_mode(mode_arg, NUMERIC, st.st_mode); + DBG(3,sprintf(output, "Using a mode of %o and a file of %s\n", mode, path)); + + if (mode == 0) { + DBG(2,sprintf(output, "Invalid mode\n")); + return INVALID_ARGS; + } + + last_ret_val = chmod(path, mode); + my_errno = errno; + return SUCCESS; + +} + + +#define USER_STATE 0 /* Specifies that the users are still being listed */ +#define MODE_STATE_ADD 1 +#define MODE_STATE_REMOVE 2 + +#define READ 00444 +#define WRITE 00222 +#define EXECUTE 00111 + +#define OWNER 00700 +#define GROUP 00070 +#define OTHER 00007 + + +mode_t +get_mode(char *arg, int type, int start_mode) +{ + int i, j,digit, total; + char c; + int state = USER_STATE; + int len = strlen(arg); + unsigned int users = 0; + unsigned int modes = 0; + + + if (type == DEFINED) { + char curr_word[10]; + + total = digit = 0; + j = 0; + DBG(4, sprintf(output, "len is %d\n", len)); + for (i=0; i < len; i++) { + if (arg[i] == '|') { + curr_word[j] = '\0'; + DBG(3, sprintf(output, "Got mode word %s\n", curr_word)); + digit = get_obj(curr_word); + if (digit < 0 ) { + DBG(2, sprintf(output, "Unable to understand mode arg %s\n", + curr_word)); + return -1; + } + total |= digit; + j = 0; + } else + curr_word[j++] = arg[i]; + } + curr_word[j] = '\0'; + DBG(3, sprintf(output, "Got mode word %s\n", curr_word)); + digit = get_obj(curr_word); + if (digit < 0 ) { + DBG(3, sprintf(output, "Unable to understand mode arg %s\n", + curr_word)); + return -1; + } + total |= digit; + return total; + } + + if (type == SYMBOLIC) { + for (i=0; i < len; i++) { + c = arg[i]; + if (state == USER_STATE) { + switch(c){ + case 'u': + users |= OWNER; + break; + case 'g': + users |= GROUP; + break; + case 'o': + users |= OTHER; + break; + case 'a': + users |= (OWNER|GROUP|OTHER); + break; + case '+': + state = MODE_STATE_ADD; + break; + case '-': + state = MODE_STATE_REMOVE; + break; + default: + return 0; + } + } else { + + switch(c){ + case 'r': + modes |= READ; + break; + case 'w': + modes |= WRITE; + break; + case 'x': + modes |= EXECUTE; + break; + default: + return 0; + } + } + } + + if (state == MODE_STATE_ADD) { + return (start_mode | (users & modes)); + } else { + return (start_mode & ~(users & modes)); + } + + } else { + /* Digits should be octal digits, so should convert */ + total = 0; + for (i=0; i < len; i++) { + c = arg[i]; + digit = atoi(&c); + if (digit > 7) + return 0; + for (j=len-i-1; j >0; j--) + digit *= 8; + total += digit; + } + return total; + } + +} + +/* + * Changes the ownership of the file. The new_id + * is of the format owner:group. Either the owner + * or the group may be omitted, but, in order to + * change the group, the : must preced the group. + */ +int sysio_chown(char *new_id, char *file) +{ + char *owner = NULL; + char *group = NULL; + uid_t o_id=-1, g_id=-1; + int len, j, i=0; + int state = 0; /* Correspond to getting owner name */ + + len = strlen(new_id); + for (i=0; i < len; i++) { + + if (new_id[i] == ':') { + /* Group name */ + if (!group) + group = malloc(strlen(new_id) -i +2); + state = 1; /* Now getting group name */ + j = 0; + if (owner) + owner[i] = '\0'; + } + + if (!state) { + /* Getting owner name */ + if (!owner) + owner = malloc(strlen(new_id) +1 ); + owner[i] = new_id[i]; + } else { + /* Group name */ + group[j] = new_id[i]; + j++; + } + } + if (group) + group[i] = '\0'; + else + owner[i] = '\0'; + + /* Are the owner and/or group symbolic or numeric? */ + if (owner) { + if (isdigit(owner[0])) { + /* Numeric -- just convert */ + o_id = (uid_t) atoi(owner); + + } else { + /* No longer support non-numeric ids */ + + DBG(2, sprintf(output, "Error: non-numeric ids unsupported\n")); + return INVALID_ARGS; + } + } + + + + if (group) { + if (isdigit(group[0])) { + /* Numeric -- just convert */ + g_id = (uid_t) atoi(group); + } else { + /* Don't support group names either */ + DBG(2, sprintf(output, "Error: non-numeric ids unsupported\n")); + return INVALID_ARGS; + } + } + + /* Now issue the syscall */ + DBG(4, sprintf(output, "Changing owner of file %s to %d (group %d)\n", + file, o_id, g_id)); + + last_ret_val = chown(file, o_id, g_id); + my_errno = errno; + return SUCCESS; +} + +int sysio_open(char *path, int flags) +{ + last_ret_val = open(path, flags); + my_errno = errno; + DBG(3, sprintf(output, "Returning with errno set to %s (ret val is %d)\n", + strerror(my_errno), (int)last_ret_val)); + return SUCCESS; +} + +int sysio_open3(char *path, int flags, char *mode_arg) +{ + mode_t mode; + + /* Is the new mode symbolic? */ + if (isalpha(mode_arg[0])) { + /* Could be specifying defines */ + if (mode_arg[0] == 'S') + mode = get_mode(mode_arg, DEFINED, 0); + else + mode = get_mode(mode_arg, SYMBOLIC, 0); + } else + mode = get_mode(mode_arg, NUMERIC, 0); + + last_ret_val = open(path, flags, mode); + my_errno = errno; + + return SUCCESS; +} + +int sysio_close(int fd) +{ + + last_ret_val = close(fd); + my_errno = errno; + return SUCCESS; +} + +int sysio_fcntl(int fd, struct cmd_map* cmdptr, char *arg) +{ + int fd_new, index, cmd, flag; + char *cmdname; + void *buf; + + cmd = cmdptr->cmd; + cmdname = cmdptr->cmd_name; + + switch(cmd) { + case F_DUPFD: + fd_new = get_obj(arg); + last_ret_val = fcntl(fd, F_DUPFD, fd_new); + my_errno = errno; + return SUCCESS; + break; + + case F_GETFD: + case F_GETFL: + case F_GETOWN: + /* case F_GETSIG: + case F_GETLEASE: */ + + last_ret_val= fcntl(fd, cmd); + my_errno = errno; + return SUCCESS; + break; + + case F_SETFD: + case F_SETFL: + case F_SETOWN: + /*case F_SETSIG: + case F_SETLEASE: + case F_NOTIFY: */ + flag = atoi(arg); + last_ret_val = fcntl(fd, cmd, flag); + my_errno = errno; + return SUCCESS; + break; + + case F_SETLK: + case F_SETLKW: + case F_GETLK: + + /* Get the buffer to hold the lock structure */ + index = get_obj(arg); + if (index < 0) { + sprintf(output, "Unable to find buffer %s\n", arg+1); + return INVALID_VAR; + } + + buf = buflist[index]; + if (!buf) { + sprintf(output, "Buffer at index %d (mapped by %s) is null\n", + index, arg); + return INVALID_VAR; + } + + last_ret_val = fcntl(fd, cmd, (struct flock *)buf); + my_errno = errno; + return SUCCESS; + default: + /* THis should be impossible */ + return INVALID_ARGS; + } + + return INVALID_ARGS; +} + +void print_stat(struct stat *st) +{ + DBG(3, sprintf(output, "%sstruct stat: \n", output)); + DBG(3, sprintf(output, "%s st_dev: %#16x\n", output, (unsigned int)st->st_dev)); + DBG(3, sprintf(output, "%s st_ino: %#16x\n", output, (unsigned int) st->st_ino)); + DBG(3, sprintf(output, "%s st_mode: %#16x\n", output, st->st_mode)); + DBG(3, sprintf(output, "%s st_nlink: %#16x\n", output, (int)st->st_nlink)); + DBG(3, sprintf(output, "%s st_uid: %#16x\n", output, st->st_uid)); + DBG(3, sprintf(output, "%s st_gid: %#16x\n", output, st->st_gid)); + DBG(3, sprintf(output, "%s st_rdev: %#16x\n", output, (int)st->st_rdev)); + DBG(3, sprintf(output, "%s st_size: %#16x\n", output, (int) st->st_size)); + DBG(3, sprintf(output, "%s st_blksize: %#16x\n", output, (int) st->st_blksize)); + DBG(3, sprintf(output, "%s st_blocks: %#16x\n", output, (int) st->st_blocks)); + DBG(3, sprintf(output, "%s st_atime: %#16x\n", output, (unsigned int) st->st_atime)); + DBG(3, sprintf(output, "%s st_mtime: %#16x\n", output, (unsigned int) st->st_mtime)); + DBG(3, sprintf(output, "%s st_ctime: %#16x", output, (unsigned int) st->st_ctime)); +} + +int sysio_fstat(int fd, void *buf) +{ + int err; + struct stat *st = (struct stat *)buf; + err = fstat(fd, st); + if (err < 0) { + my_perror("fstat"); + } + my_errno = errno; + last_ret_val = err; + print_stat(st); + + return SUCCESS; +} + +int sysio_lstat(char *filename, void *buf) +{ + int err; + struct stat *st = (struct stat *)buf; + err = lstat(filename, st); + if (err < 0) { + my_perror("lstat"); + } + + my_errno = errno; + last_ret_val = err; + print_stat(st); + return SUCCESS; +} + + +int sysio_stat(char *filename, void *buf) +{ + int err; + struct stat *st = (struct stat *)buf; + + err = stat(filename, st); + if (err < 0) { + my_perror("stat"); + } + + my_errno = errno; + last_ret_val = err; + print_stat(st); + return SUCCESS; +} + + +int sysio_getdirentries(int fd, char *buf, size_t nbytes, off_t *basep) +{ + int err; + struct dirent *dp; + + err = getdirentries(fd, buf, nbytes, basep); + last_ret_val = err; + + DBG(4, sprintf(output, "%sRead %d bytes\n", output, err)); + + dp = (struct dirent *)buf; + while (err > 0) { + DBG(3, sprintf(output, "%s\t%s: ino %llu off %llu len %x type %c\n", + output, + dp->d_name, + (unsigned long long )dp->d_ino, + (unsigned long long )dp->d_off, + dp->d_reclen, + (char )dp->d_type)); + err -= dp->d_reclen; + dp = (struct dirent *)((char *)dp + dp->d_reclen); + } + + my_errno = errno; + return last_ret_val; +} + + +int sysio_mkdir(char *path, char *mode_arg) +{ + int err; + mode_t mode; + struct stat st; + + /* Is the new mode symbolic? */ + if (isalpha(mode_arg[0])) { + /* Could be specifying defines */ + if (mode_arg[0] == 'S') + mode = get_mode(mode_arg, DEFINED, st.st_mode); + else + mode = get_mode(mode_arg, SYMBOLIC, st.st_mode); + } else + mode = get_mode(mode_arg, NUMERIC, st.st_mode); + + DBG(3, sprintf(output, "Using a mode of %o and a file of %s\n", mode, path)); + + if (mode == 0) { + DBG(2, sprintf(output, "Invalid mode\n")); + return INVALID_ARGS; + } + + err = mkdir(path, mode); + my_errno = errno; + last_ret_val = err; + return SUCCESS; + +} + +int sysio_creat(char *path, char *mode_arg) +{ + mode_t mode; + int err; + + /* Is the new mode symbolic? */ + if (isalpha(mode_arg[0])) { + /* Could be specifying defines */ + if (mode_arg[0] == 'S') + mode = get_mode(mode_arg, DEFINED, 0); + else + mode = get_mode(mode_arg, SYMBOLIC, 0); + } else + mode = get_mode(mode_arg, NUMERIC, 0); + + DBG(3, sprintf(output, "Using a mode of %o and a file of %s\n", mode, path)); + + if (mode == 0) { + DBG(2, sprintf(output, "Invalid mode\n")); + return INVALID_ARGS; + } + + err = creat(path, mode); + my_errno = errno; + last_ret_val = err; + return SUCCESS; +} + +void print_statvfs(struct statvfs *st) +{ + DBG(3, sprintf(output, "%sstruct statvfs: \n", output)); + DBG(3, sprintf(output, "%s f_bsize: %x\n", output, (unsigned int) st->f_bsize)); + DBG(3, sprintf(output, "%s f_frsize: %x\n", output, (unsigned int) st->f_frsize)); + DBG(3, sprintf(output, "%s f_blocks: %x\n", output, (unsigned int) st->f_blocks)); + DBG(3, sprintf(output, "%s f_bfree: %x\n", output, (unsigned int) st->f_bfree)); + DBG(3, sprintf(output, "%s f_bavail: %x\n", output, (unsigned int) st->f_bavail)); + DBG(3, sprintf(output, "%s f_files: %x\n", output, (unsigned int) st->f_files)); + DBG(3, sprintf(output, "%s f_ffree: %x\n", output, (unsigned int) st->f_ffree)); + DBG(3, sprintf(output, "%s f_favail: %x\n", output, (unsigned int) st->f_favail)); + DBG(3, sprintf(output, "%s f_files: %x\n", output, (unsigned int) st->f_files)); +#if (__GLIBC__ == 2 && __GLIBC_MINOR__ == 1) + DBG(3, sprintf(output, "%s f_fsid: %x\n", output, (unsigned int) st->f_fsid.__val[1])); +#else + DBG(3, sprintf(output, "%s f_fsid: %x\n", output, (unsigned int) st->f_fsid)); +#endif + DBG(3, sprintf(output, "%s f_flag: %x\n", output, (unsigned int) st->f_flag)); + DBG(3, sprintf(output, "%s f_fnamemax: %x\n", output, (unsigned int) st->f_namemax)); +} + + +int sysio_statvfs(char *filename, void *buf) +{ + int err; + struct statvfs *st = (struct statvfs *)buf; + + err = statvfs(filename, st); + if ( err == -1) { + my_perror("statvfs"); + } + + my_errno = errno; + last_ret_val = err; + + print_statvfs(st); + return SUCCESS; +} + +int sysio_fstatvfs(int fd, void *buf) +{ + int err; + struct statvfs *st = (struct statvfs *)buf; + + err = fstatvfs(fd, st); + if (err == -1) { + my_perror("fstatvfs"); + } + + my_errno = errno; + last_ret_val = err; + + print_statvfs(st); + return SUCCESS; +} + +int sysio_umask(char *mode_arg) +{ + mode_t mode; + + /* Is the new mode symbolic? */ + if (isalpha(mode_arg[0])) { + /* Could be specifying defines */ + if (mode_arg[0] == 'S') + mode = get_mode(mode_arg, DEFINED, 0); + else + mode = get_mode(mode_arg, SYMBOLIC, 0); + } else + mode = get_mode(mode_arg, NUMERIC, 0); + + last_ret_val = umask(mode); + my_errno = errno; + return SUCCESS; +} + +int sysio_mknod(char *path, char *mode_arg, dev_t dev) +{ + int err; + int mode; + + mode = get_obj(mode_arg); + + if (mode < 0) { + DBG(2,sprintf(output, "Cant get mode from %s\n", mode_arg)); + fprintf(stderr, "Cant get mode from %s\n", mode_arg); + return INVALID_VAR; + } + + err = mknod(path, (mode_t) mode, dev); + if (err < 0) + my_perror("mknod"); + + last_ret_val = err; + my_errno = errno; + return SUCCESS; +} diff --git a/libsysio/tests/test.h b/libsysio/tests/test.h new file mode 100644 index 0000000..3357802 --- /dev/null +++ b/libsysio/tests/test.h @@ -0,0 +1,46 @@ +/* + * This Cplant(TM) source code is the property of Sandia National + * Laboratories. + * + * This Cplant(TM) source code is copyrighted by Sandia National + * Laboratories. + * + * The redistribution of this Cplant(TM) source code is subject to the + * terms of the GNU Lesser General Public License + * (see cit/LGPL or http://www.gnu.org/licenses/lgpl.html) + * + * Cplant(TM) Copyright 1998-2003 Sandia Corporation. + * Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive + * license for use of this work by or on behalf of the US Government. + * Export of this program may require a license from the United States + * Government. + */ + +/* + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Questions or comments about this library should be sent to: + * + * Lee Ward + * Sandia National Laboratories, New Mexico + * P.O. Box 5800 + * Albuquerque, NM 87185-1110 + * + * lee@sandia.gov + */ + +extern int (*drvinits[])(void); + +extern int drv_init_all(void); diff --git a/libsysio/tests/test_all.pl b/libsysio/tests/test_all.pl new file mode 100755 index 0000000..25586ba --- /dev/null +++ b/libsysio/tests/test_all.pl @@ -0,0 +1,220 @@ +#!/usr/bin/perl -w + +# +# VERY basic functionality test for sysio. To run, just type ./test_all.pl +# Absolutely no guarantees for running on alpha/cplant +# + +use strict; +use FindBin; + +use Cwd 'abs_path'; + +my $alpha_arg = ""; +my $use_system = 1; +my $is_broke = 1; # Don't test certain areas known to not work on Cplant +my $arg_count = @ARGV; +foreach my $arg (@ARGV) { + if ($arg eq "-alpha") { + $alpha_arg = "-alpha"; + } elsif ($arg eq "-nosystem") { + $use_system = 0; + } +} +my $alpha_env = $ENV{"IS_ALPHA"}; +# Check the environment vars +if (defined($alpha_env) && ($alpha_env eq "yes")) { + $alpha_arg = "-alpha"; +} + +my $failures = 0; +my $success = 0; +# Get cwd.. +my $cwd = $ENV{PWD}; + +# Get tests directory +my $testdir = $FindBin::Bin; + +my $namespace_env = "SYSIO_NAMESPACE"; +my $home = $ENV{"HOME"}; +my $auto_mount = $ENV{"SYSIO_AUTOMOUNT"}; +my $root_flags = "0"; +my $extras = ""; +if ((defined($auto_mount)) && ($auto_mount == "xyes")) { + $root_flags = "2"; + + # + # Add a /auto directory for automounted file systems. We + # craft one automount that mounts /usr/home from the native + # file system. Further automounts in the sub-mounts are not enabled. + # + $extras=" \ + {mnt, dev=\"incore:0755+0+0\",dir=\"/mnt\",fl=2} \ + {creat, ft=dir,nm=\"/mnt/home\",pm=0755,ow=0,gr=0} \ + {creat, ft=file,nm=\"/mnt/home/.mount\",pm=0600, \ + str=\"native:/usr/home\"}"; +} +$ENV{$namespace_env} = "\ + {mnt, dev=\"native:/\",dir=/,fl=$root_flags} \ + {mnt, dev=\"incore:0755+0+0\",dir=\"/dev\"} \ + {creat, ft=chr,nm=\"/dev/stdin\",pm=0400,mm=0+0} \ + {creat, ft=chr,nm=\"/dev/stdout\",pm=0200,mm=0+1} \ + {creat, ft=chr,nm=\"/dev/stderr\",pm=0200,mm=0+2} \ + {creat, ft=dir,nm=\"/dev/fd\",pm=0755,ow=0,gr=0} \ + {creat, ft=chr,nm=\"/dev/fd/0\",pm=0400,mm=0+0} \ + {creat, ft=chr,nm=\"/dev/fd/1\",pm=0200,mm=0+1} \ + {creat, ft=chr,nm=\"/dev/fd/2\",pm=0200,mm=0+2} \ + {cd, dir=\"$home\"} \ + $extras "; + +my $res; + +if ($use_system == 1) { + # Will use this directory... + system("mkdir -p $cwd/tmp_dir"); + + # Create a couple of files and subdirectories for use in the tests + system("mkdir -p $cwd/tmp_dir/test1"); + system("mkdir -p $cwd/tmp_dir/test2"); + + system("cp $testdir/helper.pm $cwd/tmp_dir/test1"); +} else { + $res = `perl $testdir/setup.pl $alpha_arg $cwd`; + chop($res); + if ($res ne "setup successful") { + print "Test setup failed with $res, bailing out\n"; + exit 1; + } +} + + +if (($alpha_arg eq "") || ($is_broke == 0)) { + # Test getdirentries + $res = `perl $testdir/test_list.pl $alpha_arg $cwd/tmp_dir`; + chop($res); + if ($res ne "list test successful") { + print "Basic getdirentries test failed with message: $res\n"; + $failures++; + } else { + print "test_list finished successfully\n"; + $success++; + } +} + +# Test path +my $path1 = abs_path($testdir); +my @resarr = `perl $testdir/test_path.pl $alpha_arg $path1 $cwd $cwd/tmp_dir`; +$res = $path1.": d\n"; +if ($resarr[0] ne $res) { + print "path test returned $resarr[0] instead of $res\n"; + $failures++; +} else { + $res = $cwd.": d\n"; + if ($resarr[1] ne $res) { + print "path test returned $resarr[1] instead of $res\n"; + $failures++; + } else { + $res = $cwd."/tmp_dir: d\n"; + if ($resarr[2] ne $res) { + print "path test returned $resarr[2] instead of $res\n"; + $failures++; + } else { + print "test_path finished successfully\n"; + $success++; + } + } +} + +# Test getcwd +$res = `perl $testdir/test_getcwd.pl $alpha_arg $cwd/tmp_dir/test1`; +chop($res); +if ($res ne "getcwd test successful") { + print "getcwd test failed with message: $res\n"; + $failures++; +} else { + $success++; + print "test_getcwd finished successfully\n"; +} + +# Test copy +$res = `perl $testdir/test_copy.pl $alpha_arg $cwd/tmp_dir/test1/helper.pm $cwd/tmp_dir/helper.pm`; +chop($res); +if ($res ne "copy test successful") { + print "copy test failed with message: $res\n"; + $failures++; +} else { + $success++; + print "test_copy finished successfully\n"; +} + +# Test stats +$res = `perl $testdir/test_stats.pl $alpha_arg $use_system $cwd/tmp_dir/test1/helper.pm`; +chop($res); +if ($res ne "stat test successful") { + print "stat test failed with message: $res\n"; + $failures++; +} else { + $success++; + print "test_stats finished successfully\n"; +} + +# Test stdfd +$res = `echo "foobar" | perl $testdir/test_copy.pl $alpha_arg -o /dev/stdin /dev/stdout`; +chop($res); +if ($res ne "copy test successful") { + print "stdfd test failed with message: $res\n"; + $failures++; +} else { + $success++; + print "test_stdfd finished successfully\n"; +} + +# Test symlink +$res = `perl $testdir/test_symlink.pl $alpha_arg $cwd/tmp_dir/test1/helper.pm $cwd/tmp_dir/helper.foo`; +chop($res); +if ($res ne "Symlink test successful") { + print "symlink test failed with message: $res\n"; + $failures++; +} else { + $success++; + print "test_symlink finished successfully\n"; +} + +# Test r/w calls +$res = `perl $testdir/test_rw.pl $alpha_arg $cwd/tmp_dir/tmp.foo`; +chop($res); +if ($res ne "rw test successful") { + print "rw test failed with message: $res\n"; + $failures++; +} else { + $success++; + print "rw test finished successfully\n"; +} + +# Test strided I/O +$res = `perl $testdir/test_strided.pl $alpha_arg $cwd/tmp_dir/tmp2.foo`; +chop($res); +if ($res ne "strided IO test successful") { + print "strided IO test failed with message: $res\n"; + $failures++; +} else { + $success++; + print "strided IO test finished successfully\n"; +} + +print "$failures tests failed and $success tests succeeded\n"; + +# cleanup -- only if no failures +if ($failures == 0) { + if ($use_system == 1) { + system(`rm -rf $cwd/tmp_dir`); + } else { + $res = `perl $testdir/cleanup.pl $alpha_arg $cwd`; + chop($res); + if ($res ne "cleanup successful") { + print "Test cleanup failed with $res, bailing out\n"; + exit 1; + } + } +} +exit $failures; diff --git a/libsysio/tests/test_copy.bash b/libsysio/tests/test_copy.bash new file mode 100644 index 0000000..7217ba0 --- /dev/null +++ b/libsysio/tests/test_copy.bash @@ -0,0 +1,129 @@ +#!/bin/bash +############################################################################# +# +# This Cplant(TM) source code is the property of Sandia National +# Laboratories. +# +# This Cplant(TM) source code is copyrighted by Sandia National +# Laboratories. +# +# The redistribution of this Cplant(TM) source code is subject to the +# terms of the GNU Lesser General Public License +# (see cit/LGPL or http://www.gnu.org/licenses/lgpl.html) +# +# Cplant(TM) Copyright 1998-2003 Sandia Corporation. +# Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive +# license for use of this work by or on behalf of the US Government. +# Export of this program may require a license from the United States +# Government. +# +############################################################################# + + +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# Questions or comments about this library should be sent to: +# +# Lee Ward +# Sandia National Laboratories, New Mexico +# P.O. Box 5800 +# Albuquerque, NM 87185-1110 +# +# lee@sandia.gov + +############################################################################ +# +# File: test_copy.bash +# +# Description: Script to exercise the sysio library. +# +# Usage: +# test_copy.bash +# +# Limitations: +# 1. Doesn't exercise all of sysio. +# 2. Uses hardcoded /native prefix for file names which may not be the +# final solution. +# +############################################################################ + +# defaults - change as necessary for local system +SCRATCH=test_copy.$$ +CWD=`pwd` +SRC=${CWD}/test_copy.src +DEST=${CWD}/test_copy.dest +PREFIX=/native + +# main processing logic follows +cp /dev/null $SCRATCH +rm -f $SRC $DEST +if [ -f $SRC ] +then + echo "Could not remove $SRC - test INDETERMINATE" >> $SCRATCH + exit 5 +fi +if [ -f $DEST ] +then + echo "Could not remove $DEST - test INDETERMINATE" >> $SCRATCH + exit 5 +fi + +if ( ! cp /usr/include/stdio.h $SRC ) # just picked something handy +then + echo "Could not create source file - test INDETERMINATE" >> $SCRATCH + exit 5 +fi + + +# +# Run the test +# +./test_copy ${PREFIX}/${SRC} ${PREFIX}/${DEST} +SRC_VERF=`cksum $SRC | awk '{ print $1 }'` +DEST_VERF=`cksum $DEST | awk '{ print $1 }'` +if [ "$SRC_VERF" -ne "$DEST_VERF" ] +then + echo "The source and destination files did not match; test FAILED" >> $SCRATCH 2>&1 +else + echo "The source and destination files matched; test PASSED" >> $SCRATCH 2>&1 +fi + +# +# Report test results +# +echo "" +PASSCNT=1 +if grep "FAILED" $SCRATCH > /dev/null +then + echo "TEST $0 FAILED - found failed" + cat $SCRATCH + RC=8 +elif test `grep -c "PASSED" $SCRATCH` -ne $PASSCNT > /dev/null +then + echo "TEST $0 FAILED - wrong pass count" + cat $SCRATCH + RC=4 +else + echo "TEST $0 PASSED" + RC=0 + +fi + +if [ -z "$NOCLEANUP" ] +then + rm -f $SCRATCH $SRC $DEST +fi + +exit $RC diff --git a/libsysio/tests/test_copy.c b/libsysio/tests/test_copy.c new file mode 100644 index 0000000..bda0bd2 --- /dev/null +++ b/libsysio/tests/test_copy.c @@ -0,0 +1,198 @@ +/* + * This Cplant(TM) source code is the property of Sandia National + * Laboratories. + * + * This Cplant(TM) source code is copyrighted by Sandia National + * Laboratories. + * + * The redistribution of this Cplant(TM) source code is subject to the + * terms of the GNU Lesser General Public License + * (see cit/LGPL or http://www.gnu.org/licenses/lgpl.html) + * + * Cplant(TM) Copyright 1998-2003 Sandia Corporation. + * Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive + * license for use of this work by or on behalf of the US Government. + * Export of this program may require a license from the United States + * Government. + */ + +/* + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Questions or comments about this library should be sent to: + * + * Lee Ward + * Sandia National Laboratories, New Mexico + * P.O. Box 5800 + * Albuquerque, NM 87185-1110 + * + * lee@sandia.gov + */ + +#define _BSD_SOURCE + +#include +#include +#include +#ifndef REDSTORM +#include +#endif +#include +#include +#include +#include +#include + +#include "sysio.h" +#include "mount.h" + +#include "fs_native.h" + +#include "test.h" + +/* + * Copy one file to another. + * + * Usage: test_copy [-o] + * + * Destination will not be overwritten if it already exist. + */ + +static int overwrite = 0; /* over-write? */ + +void usage(void); +int copy_file(const char *spath, const char *dpath); + +int +main(int argc, char * const argv[]) +{ + int i; + int err; + const char *spath, *dpath; + extern int _test_sysio_startup(void); + + /* + * Parse command-line args. + */ + while ((i = getopt(argc, + argv, + "o" + )) != -1) + switch (i) { + + case 'o': + overwrite = 1; + break; + default: + usage(); + } + + if (!(argc - optind)) + usage(); + err = _test_sysio_startup(); + if (err) { + errno = -err; + perror("sysio startup"); + exit(1); + } + + /* + * Source + */ + spath = argv[optind++]; + if (!(argc - optind)) + usage(); + /* + * Destination + */ + dpath = argv[optind++]; + if (argc - optind) + usage(); + + err = copy_file(spath, dpath); + + _sysio_shutdown(); + + return err; +} + +void +usage() +{ + + (void )fprintf(stderr, + "Usage: test_copy " + " source destination\n"); + exit(1); +} + +int +open_file(const char *path, int flags, mode_t mode) +{ + int fd; + + fd = open(path, flags, mode); + if (fd < 0) + perror(path); + + return fd; +} + +int +copy_file(const char *spath, const char *dpath) +{ + int sfd, dfd; + int flags; + int rtn; + static char buf[1024]; + ssize_t cc, wcc; + + sfd = dfd = -1; + rtn = -1; + + sfd = open_file(spath, O_RDONLY, 0); + if (sfd < 0) + goto out; + flags = O_CREAT|O_WRONLY; + if (!overwrite) + flags |= O_EXCL; + dfd = open_file(dpath, flags, 0666); + if (dfd < 0) + goto out; + + while ((cc = read(sfd, buf, sizeof(buf))) > 0) + if ((wcc = write(dfd, buf, cc)) != cc) { + if (wcc < 0) { + perror(dpath); + break; + } + (void )fprintf(stderr, + "%s: short write (%u/%u)\n", + dpath, + (unsigned )wcc, + (unsigned )cc); + break; + } + if (cc < 0) + perror(spath); + +out: + if (sfd >= 0 && close(sfd) != 0) + perror(spath); + if (dfd >= 0 && (fsync(dfd) != 0 || close(dfd) != 0)) + perror(dpath); + + return 0; +} diff --git a/libsysio/tests/test_copy.pl b/libsysio/tests/test_copy.pl new file mode 100755 index 0000000..6912dcc --- /dev/null +++ b/libsysio/tests/test_copy.pl @@ -0,0 +1,218 @@ +#!/usr/bin/perl -w + +# +# copy test: Copy a file from src to dest and verify that the new file +# : is the same as the old +# + +use IPC::Open2; + +use strict; +use FindBin; +use lib "$FindBin::Bin"; +use helper; + +sub usage +{ + print "Usage: ./test_copy.pl [-alpha] : 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 = ; + $size = length($line); + } + + if ( $size > 1024) { # Arbitrary limit + $bufsize = 1024; + } else { + $bufsize = $size; + } + + my $cmdstr; + # Open src + if ($src ne "/dev/stdin") { + $cmdstr = '$src = CALL open '."$src O_RDONLY\n"; + helper::send_cmd($cmdfh, $outfh, "open", $cmdstr); + helper::verify_cmd($cmdfh, $outfh, "open $src"); + } + if ($dest ne "/dev/stdout") { + # Open dest + my $flags = "O_WRONLY|O_CREAT"; + if ($overwrite == 0) { + $flags .= "|O_EXCL"; + } + $cmdstr = '$dest = CALL open '."$dest $flags 0777\n"; + helper::send_cmd($cmdfh, $outfh, "open", $cmdstr); + my $destfile = helper::verify_cmd($cmdfh, $outfh, "open $dest"); + } + + # Allocate buffer + $cmdstr = '$buf = ALLOC '."$bufsize\n"; + helper::send_cmd($cmdfh, $outfh, "ALLOC", $cmdstr); + + # Read size bytes from src and write them out to dest + my $bytes = $size; + while ($bytes > 0) { + + my $readb; + my $res; + if ($src eq "/dev/stdin") { + # Send "delay" option to read which will give us time to + # put something in stdin (since we can't send an eof) + my $cmdstr = "CALL read ".'0 $buf '."$bytes delay\n"; + print $cmdfh $cmdstr; + # Give time to process command + sleep 1; + + # Send line from stdin + print $cmdfh $line; + sleep 0.5; + + # Make sure read was OK + $res = <$outfh>; + chop($res); + if ($res ne "0000 ") { + helper::print_and_exit($cmdfh, $outfh, 1, "ERROR! Read failed with code $res\n"); + } + + # See how many bytes we got... + $readb = helper::verify_cmd($cmdfh, $outfh, "read"); + $readb = oct($readb); + if ($readb != $bytes) { + helper::print_and_exit($cmdfh, $outfh, 0, "Short read\n"); + } + + if ($dest eq "/dev/stdout") { + $cmdstr = "CALL write ".'1 $buf '."$readb\n"; + } else { + $cmdstr = "CALL write ".'$dest $buf '."$readb\n"; + } + print $cmdfh $cmdstr; + + # Suck up the stdout... + $res = <$outfh>; + chop($res); + + $res = <$outfh>; + chop($res); + $res = oct($res); + + if ($res != 0) { + helper::print_and_exit($cmdfh, $outfh, 1, "ERROR! Write failed with code $res\n"); + } + } else { + $cmdstr = 'CALL read $src $buf '."$bufsize\n"; + helper::send_cmd($cmdfh, $outfh, "read", $cmdstr); + + $res = helper::verify_cmd($cmdfh, $outfh, "read"); + $readb = oct($res); + + # Now write $readb back out to dest + $cmdstr = 'CALL write $dest $buf '."$readb\n"; + helper::send_cmd($cmdfh, $outfh, "write", $cmdstr); + } + + $res = helper::verify_cmd($cmdfh, $outfh, "write"); + + if ($readb != oct($res)) { + print STDOUT "ERROR! Read $readb bytes but got back $res bytes\n"; + exit 1; + } + + $bytes -= $readb; + } + + # Clean up + if ($src ne "/dev/stdin") { + $cmdstr = 'CALL close $src'."\n"; + helper::send_cmd($cmdfh, $outfh, "close", $cmdstr); + } + if ($dest ne "/dev/stdout") { + $cmdstr = 'CALL close $dest'."\n"; + helper::send_cmd($cmdfh, $outfh, "close", $cmdstr); + } + if ($src ne "/dev/stdin") { + my $cmd = "cmp $src $dest " . '2>&1'; + my $cmpstr = qx($cmd); + my $exitval = $? >> 8; + if ($exitval != 0) { + if ($exitval == 1) { + print STDOUT "ERROR! File $src differs from $dest\n"; + print STDOUT "Comparison returned $cmpstr"; + } else { + print STDOUT "ERROR! File comparison failed with msg $cmpstr"; + } + exit 1; + } + } + helper::print_and_exit($cmdfh, $outfh, 0, "copy test successful\n"); +} + +my $currarg = 0; +my $is_alpha = 0; +my $overwrite = 0; + +my $len = @ARGV-2; + +if (@ARGV < 2) { + usage; +} + +my $i; +for ($i=0; $i < $len; $i++ ) { + if ($ARGV[$i] eq "-alpha") { + $is_alpha = 1; + } + if ($ARGV[$i] eq "-o") { + $overwrite = 1; + } +} + +my $src = $ARGV[$i++]; +my $dest = $ARGV[$i]; + + +process_cmd($src, $dest, $overwrite, $is_alpha); + + +exit 0; diff --git a/libsysio/tests/test_driver.c b/libsysio/tests/test_driver.c new file mode 100644 index 0000000..943cd85 --- /dev/null +++ b/libsysio/tests/test_driver.c @@ -0,0 +1,1085 @@ +#define _BSD_SOURCE +#define _XOPEN_SOURCE 600 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "sysio.h" +#include "mount.h" +#include "test.h" +#include "test_driver.h" + + +struct queue_t; + +typedef struct cmd_tree_t { + char *res_name; + char *val; + int arg_count; + struct queue_t *children; +} cmd_tree; + +struct queue_t { + char *val; + cmd_tree *cmd; + struct queue_t *next; +}; + +struct cmd_t cmd_list[] = { + {"alloc", get_buffer, usage_get_buffer}, + {"chdir", test_do_chdir, usage_chdir}, + {"checkbuf", do_checkbuf, usage_checkbuf}, + {"chmod", test_do_chmod, usage_chmod}, + {"chown", test_do_chown, usage_chown}, + {"clear", test_do_clear, usage_clear}, + {"close", test_do_close, usage_close}, + {"cmpstr", cmp_bufs, usage_cmpbufs}, + {"creat", test_do_creat, usage_creat}, + {"debug", test_do_setdebug, usage_setdebug}, + {"dup", test_do_dup, usage_dup}, + {"dup2", test_do_dup2, usage_dup2}, + {"endian", get_endian, usage_endian}, + {"exit", test_do_exit, usage_exit}, + {"fcntl", test_do_fcntl, usage_fcntl}, + {"fdatasync", test_do_fdatasync, usage_fdatasync}, + {"fill", test_do_fillbuff, usage_do_fillbuff}, + {"free", free_buffer, usage_free_buffer}, + {"fstat", test_do_fstat, usage_fstat}, + {"fstatvfs", test_do_fstatvfs, usage_fstatvfs}, + {"fsync", test_do_fsync, usage_fsync}, + {"ftruncate", test_do_ftruncate, usage_ftruncate}, + {"getcwd", test_do_getcwd, usage_getcwd}, + {"getdirentries", test_do_getdirentries, usage_getdirentries}, + {"init", test_do_init, usage_init}, + {"init_iovec", test_do_init_iovec, usage_init_iovec}, + {"init_xtvec", test_do_init_xtvec, usage_init_xtvec}, + {"ioctl", test_do_ioctl, usage_ioctl}, + {"iodone", test_do_iodone, usage_iodone}, + {"iowait", test_do_iowait, usage_iowait}, + {"ipread", test_do_ipread, usage_ipread}, + {"ipreadv", test_do_ipreadv, usage_ipreadv}, + {"ipwrite", test_do_ipwrite, usage_ipwrite}, + {"ipwritev", test_do_ipwritev, usage_ipwritev}, + {"iread", test_do_iread, usage_iread}, + {"ireadv", test_do_ireadv, usage_ireadv}, + {"ireadx", test_do_ireadx, usage_ireadx}, + {"iwrite", test_do_iwrite, usage_iwrite}, + {"iwritev", test_do_iwritev, usage_iwritev}, + {"iwritex", test_do_iwritex, usage_iwritex}, + {"list", test_do_list, usage_list}, + {"lseek", test_do_lseek, usage_lseek}, + {"lstat", test_do_lstat, usage_lstat}, + {"mkdir", test_do_mkdir, usage_mkdir}, + {"mknod", test_do_mknod, usage_mknod}, + {"mount", test_do_mount, usage_mount}, + {"open", test_do_open, usage_open}, + {"printbuf", test_do_printbuf, usage_do_printbuf}, + {"printline", test_do_printline, usage_printline}, + {"pread", test_do_pread, usage_pread}, + {"preadv", test_do_preadv, usage_preadv}, + {"pwritev", test_do_pwritev, usage_pwritev}, + {"pwrite", test_do_pwrite, usage_pwrite}, + {"quit", test_do_exit, usage_exit}, + {"read", test_do_read, usage_read}, + {"readv", test_do_readv, usage_readv}, + {"readx", test_do_readx, usage_readx}, + {"rmdir", test_do_rmdir, usage_rmdir}, + {"setbuf", do_setbuf, usage_setbuf}, + {"sizeof", get_sizeof, usage_sizeof}, + /* {"setoutput", test_do_setoutput, usage_setoutput}, */ + {"stat", test_do_stat, usage_stat}, + {"statvfs", test_do_statvfs, usage_statvfs}, + {"symlink", test_do_symlink, usage_symlink}, + {"truncate", test_do_truncate, usage_truncate}, + {"umask", test_do_umask, usage_umask}, + {"umount", test_do_umount, usage_umount}, + {"unlink", test_do_unlink, usage_unlink}, + {"write", test_do_write, usage_write}, + {"writev", test_do_writev, usage_writev}, + {"writex", test_do_writex, usage_writex}, + {NULL, NULL, NULL} +}; + +int run_cmd(cmd_tree *cmd_arg); +cmd_tree* build_tree(char **cmd, int *length, int total); +/* + * ################################################## + * # Memory functions # + * # Intended to allow users to gain access to # + * # buffers of memory to be manipulated later # + * ################################################## + */ + +void * alloc_buff32(unsigned int size, int align) +{ + void* buf; + long buf_ptr; + + /* + if ((err = memalign(&buf, align, size)) != 0) { + perror("memalign"); + return 0; + } + */ + size += align; + buf = malloc(size); + align--; + DBG(3, fprintf(outfp, "Buf is at %p\n", (void *)buf)); + buf_ptr = (long)buf + ((long)buf & align); + + DBG(3, fprintf(outfp, "Buf is at %p\n", (void *)buf_ptr)); + return (void *)buf_ptr; +} + +void free_buf32(void * ptr) +{ + free(ptr); +} + +long alloc_buff64(unsigned int size, int align) +{ + char * buf; + long ret_value; + + /* + if (memalign((void **)&buf, align, size)) + return 0; + */ + size += align; + buf = malloc(size); + align--; + ret_value = (long)buf + ((long)buf & align); + return ret_value; +} + +void free_buf64(long ptr) +{ + free((char *)ptr); +} + + +/* + * Hash function for variables. Shamelessly stolen + * from the ext3 code + */ +unsigned int dx_hack_hash (const char *name, int len) +{ + unsigned int hash0 = 0x12a3fe2d, hash1 = 0x37abe8f9; + while (len--) + { + unsigned int hash = hash1 + (hash0 ^ (*name++ * 7152373)); + if (hash & 0x80000000) hash -= 0x7fffffff; + hash1 = hash0; + hash0 = hash; + } + return hash0; +} + +struct var_mapping *get_map(char *var_name) +{ + int index; + struct var_mapping_list *curr; + + + if (var_name[0] == '$') { + /* It is a name--chop off the initial and get the mapping $ */ + var_name++; + } + + index = dx_hack_hash(var_name, strlen(var_name)); + index %= MAX_VARS -1; + + DBG(5, fprintf(outfp, "Got index of %d for %s\n", index, var_name)); + curr = &map[index]; + + while ((curr) && (curr->map.obj != -1) ) { + if ( (curr->map.name == NULL) || (strcmp(curr->map.name, var_name)) ) + curr = curr->next; + else + return &curr->map; + } + + return NULL; +} + +char *get_str(char *var_name) +{ + /* See if it is a quoted string */ + if (var_name[0] == '"') { + /* Chop off the beginning and end quotes and return the string */ + int len = strlen(var_name); + var_name[len-1] = '\0'; + var_name++; + } + + return var_name; +} + +static char* +get_or_part(char **str, int* did_alloc) +{ + char *tmp_str = *str; + int i, norm_str=0; + + if (tmp_str == NULL) + return NULL; + + if (tmp_str[0] == '|') { + tmp_str++; + norm_str=1; + } + + for (i=0; (unsigned int)i < strlen(tmp_str); i++) { + if (tmp_str[i] == '|') { + char *new_str = (char *)malloc(i+1); + memcpy(new_str, tmp_str, i); + new_str[i] = '\0'; + *did_alloc = 1; + *str = &tmp_str[i]; + return new_str; + } + } + + if (norm_str) { + *did_alloc = 0; + *str = NULL; + return tmp_str; + } + + return NULL; +} + +int get_obj(char *var_name) +{ + char** str = &var_name; + char *str1; + struct var_mapping *var_map; + int did_alloc=0; + int obj=0, got_obj=0; + + DBG(5, fprintf(outfp, "Getting object for %s\n", var_name)); + + /* If var_name is a digit, we assume it is a literal */ + if (isdigit(var_name[0])) + return atoi(var_name); + + /* + * Check for '|', indicates that one or more values are or'd + * together + */ + while ((str1 = get_or_part(str, &did_alloc)) != NULL) { + + if (isdigit(str1[0])) { + if (str1[0] == '0') { + /* Assume octal format */ + obj |= strtol(str1, NULL, 8); + } else + obj |= atoi(str1); + } else { + var_map = get_map(str1); + if (!var_map) { + if (did_alloc) + free(str1); + return -1; + } + obj |= var_map->obj; + } + + if (did_alloc) { + did_alloc = 0; + free(str1); + } + got_obj++; + } + + if (got_obj) + return obj; + + var_map = get_map(var_name); + if (!var_map) + return -1; + else + return var_map->obj; +} + + +void store_result(char *var_name, int result) +{ + int index = dx_hack_hash(var_name, strlen(var_name)); + struct var_mapping_list *map_obj; + struct var_mapping_list *new_map; + index %= MAX_VARS -1 ; + + if (map[index].map.obj >= 0) { + + /* Got a collision --just chain it*/ + new_map = malloc(sizeof(struct var_mapping_list)); + + map_obj = &map[index]; + while (map_obj->next != NULL) + map_obj = map_obj->next; + + map_obj->next = new_map; + } else + new_map = &map[index]; + + new_map->map.name = malloc(strlen(var_name) + 1); + strcpy(new_map->map.name, var_name); + new_map->map.obj = result; + new_map->map.type = last_type; + new_map->next = NULL; + DBG(3, fprintf(outfp, "Stored %d in index %d hashed with %s\n", + result, index, var_name)); +} + +void free_obj(char *obj_name) +{ + int index; + struct var_mapping_list *prev, *curr; + + + /* See if it is a variable name */ + if (obj_name[0] == '$') { + /* It is a name--chop off the initial $ */ + obj_name++; + } + index = dx_hack_hash(obj_name, strlen(obj_name)); + index %= MAX_VARS -1; + + DBG(5, fprintf(outfp, "Got index of %d\n", index)); + curr = &map[index]; + + prev = NULL; + + while ((curr) && (curr->map.obj != -1) ) { + if (strcmp(curr->map.name, obj_name)) { + prev = curr; + curr = curr->next; + } else + break; + } + + /* Remove the object from the chain */ + if (prev) + prev->next = curr->next; + + curr->map.obj = -1; + free(curr->map.name); + if (prev) + free(curr); +} + + +/* + * Given a long string, returns the string divided into + * whitespace seperated words in list. Returns the number + * of words + */ +int parser(char *str, char** list) +{ + int len, i=0, j=0, counter=-1; + int in_quotes = 0; + char *new_str; + + + len = strlen(str); + DBG(5, fprintf(outfp, "str is %s len is %d\n", str, len)); + while (i < len) { + + if ((i==0) || ((str[i] == ' ') && (in_quotes == 0)) ) { + if (i != 0) { + new_str[j] = '\0'; + DBG(5, fprintf(outfp, "Got word %s\n", list[counter])); + i++; + } + while ((str[i] == ' ') && (in_quotes == 0)) + i++; + counter++; + new_str = list[counter] = malloc(MAX_WORD); + j = 0; + + } + + new_str[j] = str[i]; + if (str[i] == '"') { + if (in_quotes) + in_quotes = 0; + else + in_quotes = 1; + } + if ((str[i] == ' ') && (in_quotes==0)){ + while (str[i+1] == ' ') + i++; + new_str[j] = '\0'; + } + i++; + j++; + + } + new_str[j] = '\0'; + DBG(5, fprintf(outfp, "Got word %s\n", list[counter])); + return counter +1; +} + + +int execute_cmd(char *cmd, char **args, int arg_count) +{ + int i = 0; + + if (!strcmp(cmd, "help")) { + if (arg_count > 0) { + while(cmd_list[i].cmd != NULL) { + if (!strcmp(cmd_list[i].cmd, args[0])) { + (cmd_list[i].usage)(); + return 0; + } + i++; + } + } else { + do_help(); + return 0; + } + return -1; + } + while(cmd_list[i].cmd != NULL) { + if (!strcmp(cmd_list[i].cmd, cmd)) { + return (cmd_list[i].func)(arg_count, args); + } + i++; + } + DBG(2, fprintf(outfp, "Command %s was invalid\n", cmd)); + return INVALID_CMD; +} + +int get_args(struct queue_t *child, char** list, int num_args, int argnum) +{ + char *argval; + + if (child->val != NULL) { + argval = child->val; + } else if (child->cmd != NULL) { + run_cmd(child->cmd); + if (child->cmd->res_name != NULL) + argval = child->cmd->res_name; + else { + char tmpstr[50]; + int val = last_ret_val; + sprintf(tmpstr, "%x", val); + argval = tmpstr; + } + } else { + DBG(2, fprintf(outfp, "I am confused\n")); + return INVALID_ARGS; + } + + list[argnum] = malloc(strlen(argval) + 1); + strcpy(list[argnum], argval); + argnum++; + + if (argnum == num_args) + return SUCCESS; + else if (child->next == NULL) { + DBG(2, fprintf(outfp, "Only on arg number %d out of %d, but ran out of children\n", + argnum, num_args)); + return INVALID_ARGS; + } else + return get_args(child->next, list, num_args, argnum); + + return SUCCESS; +} + +int run_cmd(cmd_tree *cmd_arg) +{ + char cmdstr[MAX_COMMAND]; + char *cmdptr; + char **args; + int res, i; + struct buf_t *buf; + char *cmd; + struct queue_t *child; + + if (cmd_arg == NULL) + return INVALID_CMD; + + cmd = cmd_arg->val; + cmdptr = cmdstr; + child = cmd_arg->children; + if ( (!strcmp("exit", cmd)) || (!strcmp("quit", cmd)) || + (!strcmp("EXIT", cmd)) || (!strcmp("QUIT", cmd)) ) + strcpy(cmdstr, "exit"); + else if (!strcmp("ALLOC", cmd)) + strcpy(cmdstr, "alloc"); + else if (!strcmp("FREE", cmd)) + strcpy(cmdstr, "free"); + else if (!strcmp("HELP", cmd)) + strcpy(cmdstr, "help"); + else if (!strcmp("CALL", cmd)) { + if (cmd_arg->arg_count < 1) { + DBG(2, fprintf(outfp, "Need at least one command\n")); + return INVALID_CMD; + } + + cmd_arg->arg_count--; + if (child->val != NULL) + cmdptr = child->val; + else { + DBG(2, fprintf(outfp, "Need to specify command\n")); + return INVALID_CMD; + } + + DBG(3, fprintf(outfp, "Got cmd %s\n", child->val)); + if (cmd_arg->arg_count != 0) + child = child->next; + + + } else if (!strcmp("DEPOSIT", cmd)) + strcpy(cmdstr, "fill"); + else if (!strcmp("PRINT", cmd)) + strcpy(cmdstr, "printbuf"); + else { + if (cmd_arg->res_name != NULL) { + /* + * If the cmd is not a valid command, just store it + */ + res = get_obj(cmd_arg->children->val); + last_type = UINT; + if (res < 0) { + /* Just store it as a string */ + buf = (struct buf_t *)malloc(sizeof(struct buf_t)); + buf->len = strlen(cmd); + buf->buf = (char *)malloc(buf->len+1); + strcpy(buf->buf, cmd_arg->children->val); + buflist[next] = buf; + res = next; + DBG(3, fprintf(outfp, "Stored %s in index %d\n", (char *)buf->buf, next)); + next++; + last_type = STR; + } + store_result(cmd_arg->res_name, res); + return SUCCESS; + } else + return INVALID_CMD; + } + + + if (cmd_arg->arg_count == 0) + args = NULL; + else { + args = (char **)malloc(sizeof(char *)*cmd_arg->arg_count); + get_args(child, args, cmd_arg->arg_count, 0); + } + + DBG(3, fprintf(outfp, "CMD: %s\n ARGS: ",cmdptr)); + for (i=0; i < cmd_arg->arg_count; i++) + DBG(3, fprintf(outfp, "%s ", args[i])); + DBG(3, fprintf(outfp, "\n")); + res = execute_cmd(cmdptr, args, cmd_arg->arg_count); + if (cmd_arg->res_name != NULL) + store_result(cmd_arg->res_name, last_ret_val); + + return res; +} + + +int is_command(char *name) +{ + if ( (strcmp(name, "CALL")) && (strcmp(name, "FILL")) && + (strcmp(name, "ALLOC")) && (strcmp(name, "PRINT")) && + (strcmp(name, "FREE")) && (strcmp(name, "exit")) && + (strcmp(name, "HELP")) && (strcmp(name, "help")) && + (strcmp(name, "quit")) && (strcmp(name, "EXIT")) && + (strcmp(name, "QUIT")) && (strcmp(name, "DEPOSIT")) ) + return 0; + + return 1; +} + +#define ARGS 1 +int get_type(char *arg0) +{ + if ((arg0[0] == '(') || (is_command(arg0)) ){ + return 2; + } + + return ARGS; +} + + +int add_args(char **cmd, int length, int total, cmd_tree *tree) +{ + int new_len, type; + struct queue_t *old, *new; + + old = tree->children; + while ((old) && (old->next)) + old = old->next; + new = (struct queue_t *)malloc(sizeof(struct queue_t)); + if (old) + old->next = new; + else + tree->children = new; + new->next = NULL; + + type = get_type(cmd[0]); + if (type < 0) { + DBG(2, fprintf(outfp, "Don't understand %s\n", cmd[0])); + return INVALID_CMD; + } + if (type == ARGS) { + new->val = (char *)malloc(strlen(cmd[0])+1); + strcpy(new->val, cmd[0]); + new->cmd = NULL; + total = 1; + } else { + new_len = length; + if (cmd[0][0] == '(') { + new_len--; + } + + new->val = NULL; + new->cmd = build_tree(&cmd[1], &new_len, total); + if (new->cmd == NULL) { /* Invalid command */ + return length; /* Pretend we used everything up */ + } + total = (length - new_len); + DBG(4, fprintf(outfp, "Used %d bytes\n", total)); + } + + return total; +} + +void free_tree(cmd_tree* tree) +{ + if (!tree) + return; + + if (tree->children) { + struct queue_t *child = tree->children; + struct queue_t *next; + do { + next = child->next; + if (child->cmd) + free_tree(child->cmd); + free(child->val); + free(child); + child = next; + } while (child); + } + + if (tree->res_name) + free(tree->res_name); + + if (tree->val) + free(tree->val); + + free(tree); +} + +cmd_tree* build_tree(char **cmd, int *length, int total) +{ + int index = 0, used_args = 0; + cmd_tree *tree; + if ((*length < 0) || (!cmd) || (*cmd == NULL)) + return NULL; + + + DBG(4, fprintf(outfp, "length is %d\n", *length)); + tree = (cmd_tree *)malloc(sizeof(cmd_tree)); + tree->res_name = NULL; + tree->children = NULL; + if (cmd[index][0] == '$') { + tree->res_name = (char *)malloc(strlen(cmd[index])+1); + strcpy(tree->res_name, (char*)(cmd[index]+1)); + index++; + if (cmd[index][0] == '=') + index++; + } else + tree->res_name = NULL; + + if (is_command(cmd[index]) == 0) { + if (tree->res_name == NULL) { + DBG(2, fprintf(outfp, "command %s is invalid \n", cmd[index])); + return NULL; + } + } + + tree->val = (char *)malloc(strlen(cmd[index])+1); + strcpy(tree->val, cmd[index]); + index++; + *length -= index; + tree->arg_count = 0; + + if (*length == 0) { + /* All done! */ + return tree; + } + + /* Got to get the arguments */ + while (*length > 0) { + + if (cmd[index][0] == ')') { + *length = *length-1; + DBG(4, fprintf(outfp, "and now len is %d\n", *length)); + return tree; + } + + used_args = add_args(&cmd[index], *length, total, tree); + tree->arg_count++; + *length -= used_args; + index += used_args; + } + + return tree; +} + +char *line; +char *getline(char *prompt) +{ + int i=-1; + int count=0; + + line = malloc(MAX_LINE); + if ((do_prompt) && (infp == stdin)) + printf(prompt); + + do { + /* If we get an end of file, just wait */ + if (feof(infp)) { + while (feof(infp) && (line[i] != '\n')) { + clearerr(infp); + count++; + fseek(infp, 0, SEEK_CUR); + } + } else { + i++; + } + fread(&line[i], 1, 1, infp); + } while(line[i] != '\n'); + + line[i] = '\0'; + + /* fprintf(stderr, "Got word %s\n", line); */ + DBG(5, fprintf(outfp, "Got word %s\n", line)); + return line; +} + +void my_perror(char *msg) +{ + char *errmsg = strerror(errno); + + DBG(2, fprintf(outfp, "%s: %s\n", msg, errmsg)); +} + +/* Static list of flag names */ +struct var_mapping flags_map[] = { + {"O_RDONLY", O_RDONLY, UINT }, + {"O_WRONLY", O_WRONLY, UINT }, + {"O_RDWR", O_RDWR, UINT }, + {"O_CREAT", O_CREAT, UINT }, + {"O_EXCL", O_EXCL, UINT }, + {"O_NOCTTY", O_NOCTTY, UINT }, + {"O_TRUNC", O_TRUNC, UINT }, + {"O_APPEND", O_APPEND, UINT }, + {"O_SYNC", O_NONBLOCK, UINT }, + {"O_NDELAY", O_NDELAY, UINT }, + {"O_SYNC", O_SYNC, UINT }, + {"O_FSYNC", O_FSYNC, UINT }, + {"O_ASYNC", O_ASYNC, UINT }, + {"SEEK_SET", SEEK_SET, UINT }, + {"SEEK_CUR", SEEK_CUR, UINT }, + {"SEEK_END", SEEK_END, UINT }, + {"S_ISUID", S_ISUID, UINT }, + {"S_ISGID", S_ISGID, UINT }, + {"S_ISVTX", S_ISVTX, UINT }, + {"S_IRWXU", S_IRWXU, UINT }, + {"S_IRUSR", S_IRUSR, UINT }, + {"S_IREAD", S_IREAD, UINT }, + {"S_IWUSR", S_IWUSR, UINT }, + {"S_IWRITE", S_IWRITE, UINT }, + {"S_IXUSR", S_IXUSR, UINT }, + {"S_IEXEC", S_IEXEC, UINT }, + {"S_IRWXG", S_IRWXG, UINT }, + {"S_IRGRP", S_IRGRP, UINT }, + {"S_IWGRP", S_IWGRP, UINT }, + {"S_IXGRP", S_IXGRP, UINT }, + {"S_IRWXO", S_IRWXO, UINT }, + {"S_IROTH", S_IROTH, UINT }, + {"S_IWOTH", S_IWOTH, UINT }, + {"S_IXOTH", S_IXOTH, UINT }, + {"S_IFCHR", S_IFCHR, UINT }, + {"S_IFMT", S_IFMT, UINT }, + {"S_IFBLK", S_IFBLK, UINT }, + {"S_IFREG", S_IFREG, UINT }, + {"S_IFIFO", S_IFIFO, UINT }, + {"S_IFLNK", S_IFLNK, UINT }, + { NULL, -1, SINT } +}; + +void init_map() +{ + int index = 0; + + while (flags_map[index].obj != -1) { + store_result(flags_map[index].name, flags_map[index].obj); + index++; + } +} + +int getquotedlen(char *str) +{ + int i; + + if (str[0] != '"' && str[0] != '\'') + return -1; + + for (i=1; str[i] != '\0' && str[i] != '"' && str[i] != '\''; i++); + + return i; +} + +int perform_op(int num1, int num2, char op) +{ + switch(op) { + + case '+': + return num1 + num2; + break; + + case '*': + return num1 * num2; + break; + + case '/': + return num1 / num2; + break; + + case '-': + return num1 - num2; + break; + + case '%': + return num1%num2; + break; + + default: + return num1; + } + return 0; +} + +int get_constant_val(char **str_ptr, int type) +{ + struct buf_t *buf; + char *buf_ptr; + char *str = *str_ptr; + char ch; + int i, j, num1, num2, size; + + printf("Getting constant val from %s\n", str); + switch(type) { + case 1: + size = getquotedlen(str); + buf = (struct buf_t *)malloc(sizeof(struct buf_t)); + buf->buf = alloc_buff32(size, 8); + buf->len = size; + buf_ptr = buf->buf; + buflist[next] = buf; + j=0; + for (i=1; i < size; i++) { + buf_ptr[j] = str[i]; + j++; + } + buf_ptr[j] = '\0'; + + DBG(3, fprintf(outfp, "Your buffer (%p) (%p) is at index %d\n", + (void *)buf, buf->buf, next)); + next++; + + last_type = PTR; + last_ret_val = next-1; + return last_ret_val; + break; + + case 2: + if (str[0] == '$') { + num1 = get_obj(str); + } else { + num1 = atoi(str); + } + str = str_ptr[1]; + ch = str_ptr[1][0]; + if ((ch == '+') || (ch == '/') || (ch == '*') || + (ch == '-') || (ch == '%')) { + if (str_ptr[2][0] == '$') + num2 = get_obj(str_ptr[2]); + else + num2 = atoi(str_ptr[2]); + num1 = perform_op(num1, num2, ch); + } + + last_type = UINT; + last_ret_val = num1; + + break; + + default: + DBG(2, fprintf(outfp, "Can't understand type of %d\n", type)); + return INVALID_ARGS; + } + + return last_ret_val; +} + +int is_constant(char *str) +{ + if ((str[0] == '"') || (str[0] == '\'')) + return 1; + + + if ( (str[0] == '$') || + ( ((int)str[0] > 47) && ((int)str[0] < 57) ) ) + return 2; + + return 0; +} + +int main(int argc, char *argv[]) +{ + int count, err, i, orig_count; + char *input, *name; + char **cmd; + cmd_tree *tree; + extern int _test_sysio_startup(void); + + /* + * Init sysio lib. + */ + err = _test_sysio_startup(); + + /* Temp. hack until I do the right thing to fix this...*/ + open("/dev/stdin",O_RDONLY); + open("/dev/stdout",O_WRONLY); + open("/dev/stderr",O_WRONLY); + + infp = stdin; + outfp = stdout; + + do_prompt = 1; + + errno = 0; + /* Get the input/output streams */ + for (i = 1; i < argc; i++) { + if (!strcmp(argv[i], "--input")) { + i++; + infp = fopen(argv[i], "r"); + if (!infp) { + fprintf(outfp, "Unable to open file %s for reading\n", argv[i]); + return -1; + } + } else if (!strcmp(argv[i], "--output")) { + i++; + outfp = fopen(argv[i], "w"); + if (!outfp) { + fprintf(stderr, "Unable to open file %s for writing\n", argv[i]); + return -1; + } + } else if (!strcmp(argv[i], "--np")) { + do_prompt = 0; + } else { + fprintf(stderr, "%s: Invalid arg\n", argv[i]); + return -1; + } + } + /* Initilize the mapping */ + for (i=0; i < MAX_VARS; i++) + map[i].map.obj = -1; + + /* Debug defaults */ + debug_level = 1; + print_line = 0; + + +#if 0 + /* sysio defaults */ + strcpy(root_driver, DEFAULT_DRIVER); + strcpy(mntpath, "/"); + mntflgs = 0; +#endif + + my_errno = 0; + + /* Set up line buffering */ + setlinebuf(outfp); + setlinebuf(infp); + + /* + * This sets up some common flags so that the string + * names can be used (for instance 0_RDWR, SEEK_SET, etc + */ + init_map(); + i=0; + next = 0; + while (1) { + bzero(output, 4096); + + input = getline("> "); + cmd = malloc(MAX_COMMAND * sizeof(char *)); + count = orig_count = parser(input, cmd); + name = NULL; + if ((!count) || (count > MAX_COMMAND)){ + fprintf(outfp, "%s: invalid command\n", input); + } else { + i = 0; + if (cmd[0][0] == '$') { + /* Need to store output of command in var name */ + name = cmd[0]+1; + DBG(4, fprintf(outfp, "name is %s\n", name)); + count--; + /* The '=' is not necessary, but available */ + if (!strcmp(cmd[1], "=")){ + i++; + count--; + } + i++; + if ((err=is_constant(cmd[i])) != 0) { + store_result((char *)(&cmd[0][1]), get_constant_val(&cmd[i], err)); + tree = NULL; + err = 0; + } else { + + tree = build_tree(&cmd[i], &count, 0); + if (tree != NULL) { + err = run_cmd(tree); + store_result((char *)(&cmd[0][1]), last_ret_val); + } + } + } else { + + tree = build_tree(cmd, &count, 0); + if (tree != NULL) + err = run_cmd(tree); + } + /* Print out return code and any string from command */ + fprintf(outfp, "%#04x %s\n", err, output); + if (tree) + free_tree(tree); + /* fprintf(stderr, "%#04x %s\n", err, output); */ + for (i=0; i < count; i++) + free(cmd[i]); + } + free(cmd); + free(line); + } +} diff --git a/libsysio/tests/test_driver.h b/libsysio/tests/test_driver.h new file mode 100644 index 0000000..d8fabaf --- /dev/null +++ b/libsysio/tests/test_driver.h @@ -0,0 +1,301 @@ +/* + * I feel like I should be putting a comment here... + */ +#include +#include "test.h" + +/* Debugging stuff.. */ +#define PRINT_LINE 0 +int debug_level; +int print_line; + +FILE *outfp; /* output file */ +FILE *infp; + +#define DBG(level, _x) \ + do { \ +if (((level) <= (debug_level))) { \ + if (print_line) \ + fprintf(outfp, "From file %s line %d: \n", __FILE__, __LINE__); \ + (void)((_x)); \ +} \ +} while(0) + +/* Maximum size of a command or command argument */ +#define MAX_WORD 150 + +/* Maximum size of an input line */ +#define MAX_LINE 300 + +/* Structure to hold commands in */ +struct cmd_t { + char *cmd; + int (*func)(int, char **); + void (*usage)(); +}; + +extern struct cmd_t cmd_list[]; + +/* Maximum number of words in a command (command + command args) */ +#define MAX_COMMAND 50 + +/* + * Holds list of allocated buffers. To use a pre-allocated + * buffer, the index number needs to be passed in. This should + * probably be smarter--perhaps a hash table could store the + * list, with the hash being sent back to the user + */ +#define MAX_BUFFERS 50 +struct buf_t { + void *buf; + int len; +}; + +struct buf_t *buflist[MAX_BUFFERS]; + +int next; /* Next available buffer slot */ + + +/* Defaults for libsysio */ +char root_driver[75]; +char mntpath[250]; +unsigned int mntflgs; + + + +#define MAX_VARS 250 + +/* + * Valid types for fill buff and variables. + */ +#define UINT 0 +#define SINT 1 +#define STR 2 +#define PTR 3 +/* + * This defines a mapping from a variable name to + * some object known by the test harness. Variable + * names are distinguished by '$'. Variables are used + * in two possible ways: to capture the output of + * a function, as in $my_fd = open name, or to gain + * access to that variable, as in open $my_fd. Variables + * do not necessarily have to be initilized before use + */ +struct var_mapping { + char *name; /* Variable name */ + int obj; /* Object will always be an integer -- either a + file descriptor or an index into the buffer + array + */ + int type; +}; + +int last_type; + +struct var_mapping_list { + struct var_mapping map; + struct var_mapping_list *next; +}; + +/* + * Again, I am lazy and just use a static array + * This should be dynamically remappable + */ +struct var_mapping_list map[MAX_VARS]; +char output[4096]; +int pos; /* Pos in output string */ + +struct cmd_map { + char *cmd_name; + int cmd; + int num_args; +}; + +extern struct cmd_map fcntl_cmds[]; + +/* Return code information */ +#define SUCCESS 0x000 +#define INVALID_ARGS 0x001 +#define INVALID_CMD 0x002 +#define INVALID_VAR 0x004 + +int do_prompt; /* Prompt for interactive run? */ +int last_ret_val; /* Last return value returned by libsysio call */ +extern int errno; +int my_errno; /* Not sure what the difference will be */ + +/* Functions defined in test_driver.c */ +extern unsigned int dx_hack_hash (const char *name, int len); +extern int get_obj(char *var_name); +extern void *alloc_buff32(unsigned int size, int align); +extern void store_result(char *var_name, int result); +extern struct var_mapping *get_map(char *var_name); +extern void free_obj(char *obj_name); +extern void my_perror(char *msg); +extern char *get_str(char *var_name); + +/* Stub functions defined in sysio_stubs.c */ +extern int test_do_setdebug(int argc, char **argv); +extern int test_do_printline(int argc, char **argv); +extern int cmp_bufs(int argc, char **argv); +extern int test_do_printbuf(int argc, char **argv); +extern int test_do_fillbuff(int argc, char **argv); +extern int test_do_mount(int argc, char **args); +extern int test_do_list(int argc, char **args); +extern int test_do_init(int argc, char **args); +extern int get_endian(int argc, char **args); +extern int get_sizeof(int argc, char **args); +extern int do_setbuf(int argc, char **argv); +extern int test_do_exit(int argc, char **args); +extern int get_buffer(int argc, char **args); +extern int free_buffer(int argc, char **args); +extern int test_do_chdir(int argc, char **args); +extern int do_checkbuf(int argc, char **argv); +extern int test_do_chmod(int argc, char **args); +extern int test_do_chown(int argc, char **args); +extern int test_do_open(int argc, char **args); +extern int test_do_close(int argc, char **args); +extern int test_do_clear(int argc, char **argv); +extern int test_do_dup(int argc, char **args); +extern int test_do_dup2(int argc, char **args); +extern int test_do_fcntl(int argc, char **args); +extern int test_do_fstat(int argc, char **argv); +extern int test_do_fsync(int argc, char **argv); +extern int test_do_ftruncate(int argc, char **argv); +extern int test_do_getcwd(int argc, char **argv); +extern int test_do_init_iovec(int argc, char **argv); +extern int test_do_init_xtvec(int argc, char **argv); +extern int test_do_lseek(int argc, char **argv); +extern int test_do_lstat(int argc, char **argv); +extern int test_do_getdirentries(int argc, char **argv); +extern int test_do_mkdir(int argc, char **argv); +extern int test_do_creat(int argc, char **argv); +extern int test_do_stat(int argc, char **argv); +extern int test_do_statvfs(int argc, char **argv); +extern int test_do_fstatvfs(int argc, char **argv); +extern int test_do_truncate(int argc, char **argv); +extern int test_do_rmdir(int argc, char **argv); +extern int test_do_symlink(int argc, char **argv); +extern int test_do_unlink(int argc, char **argv); +extern int test_do_fdatasync(int argc, char **argv); +extern int test_do_ioctl(int argc, char **argv); +extern int test_do_umask(int argc, char **argv); +extern int test_do_iodone(int argc, char **argv); +extern int test_do_iowait(int argc, char **argv); +extern int test_do_ipreadv(int argc, char **argv); +extern int test_do_ipread(int argc, char **argv); +extern int test_do_preadv(int argc, char **argv); +extern int test_do_pread(int argc, char **argv); +extern int test_do_ireadv(int argc, char **argv); +extern int test_do_ireadx(int argc, char **argv); +extern int test_do_iread(int argc, char **argv); +extern int test_do_readv(int argc, char **argv); +extern int test_do_readx(int argc, char **argv); +extern int test_do_read(int argc, char **argv); +extern int test_do_ipwritev(int argc, char **argv); +extern int test_do_ipwrite(int argc, char **argv); +extern int test_do_pwritev(int argc, char **argv); +extern int test_do_pwrite(int argc, char **argv); +extern int test_do_iwritev(int argc, char **argv); +extern int test_do_iwrite(int argc, char **argv); +extern int test_do_iwritex(int argc, char **argv); +extern int test_do_writev(int argc, char **argv); +extern int test_do_writex(int argc, char **argv); +extern int test_do_write(int argc, char **argv); +extern int test_do_mknod(int argc, char **argv); +extern int test_do_umount(int argc, char **argv); + + +/* Functions defined in sysio_tests.c */ +extern int sysio_mount(char *from, char *to); +extern int sysio_list(char *path); +extern int initilize_sysio(void); +extern int sysio_chdir(char *newdir); +extern int sysio_chmod(char *mode_arg, const char *path); +extern int sysio_chown(char *new_id, char *file); +extern int sysio_open(char *path, int flags); +extern int sysio_open3(char *path, int flags, char *mode_arg); +extern int sysio_close(int fd); +extern int sysio_fcntl(int fd, struct cmd_map* cmdptr, char *arg); +extern int sysio_fstat(int fd, void *buf); +extern int sysio_lstat(char *filename, void *buf); +extern int sysio_getdirentries(int fd, char *buf, size_t nbytes, off_t *basep); +extern int sysio_mkdir(char *path, char *mode); +extern int sysio_creat(char *path, char *mode_arg); +extern int sysio_stat(char *filename, void *buf); +extern int sysio_statvfs(char *filename, void *buf); +extern int sysio_fstatvfs(int fd, void *buf); +extern int sysio_umask(char *mode_arg); +extern int sysio_mknod(char *path, char *mode_arg, dev_t dev); + +/* Usage functions defined in help.c */ +extern void do_help(); +extern void usage_setdebug(); +extern void usage_printline(); +extern void usage_endian(); +extern void usage_sizeof(); +extern void usage_get_buffer(); +extern void usage_free_buffer(); +extern void usage_do_printbuf(); +extern void usage_do_fillbuff(); +extern void usage_init(); +extern void usage_list(); +extern void usage_chdir(); +extern void usage_chmod(); +extern void usage_chown(); +extern void usage_open(); +extern void usage_close(); +extern void usage_clear(); +extern void usage_mount(); +extern void usage_dup(); +extern void usage_dup2(); +extern void usage_fcntl(); +extern void usage_fstat(); +extern void usage_fsync(); +extern void usage_ftruncate(); +extern void usage_getcwd(); +extern void usage_init_iovec(); +extern void usage_init_xtvec(); +extern void usage_lseek(); +extern void usage_lstat(); +extern void usage_getdirentries(); +extern void usage_mkdir(); +extern void usage_checkbuf(); +extern void usage_cmpbufs(); +extern void usage_creat(); +extern void usage_setbuf(); +extern void usage_stat(); +extern void usage_statvfs(); +extern void usage_fstatvfs(); +extern void usage_truncate(); +extern void usage_rmdir(); +extern void usage_symlink(); +extern void usage_unlink(); +extern void usage_fdatasync(); +extern void usage_ioctl(); +extern void usage_umask(); +extern void usage_iowait(); +extern void usage_iodone(); +extern void usage_ipreadv(); +extern void usage_ipread(); +extern void usage_preadv(); +extern void usage_pread(); +extern void usage_ireadv(); +extern void usage_iread(); +extern void usage_ireadx(); +extern void usage_readv(); +extern void usage_readx(); +extern void usage_read(); +extern void usage_ipwritev(); +extern void usage_ipwrite(); +extern void usage_pwritev(); +extern void usage_pwrite(); +extern void usage_iwritev(); +extern void usage_iwrite(); +extern void usage_iwritex(); +extern void usage_writev(); +extern void usage_write(); +extern void usage_writex(); +extern void usage_mknod(); +extern void usage_umount(); +extern void usage_exit(); diff --git a/libsysio/tests/test_getcwd.c b/libsysio/tests/test_getcwd.c new file mode 100644 index 0000000..340180e --- /dev/null +++ b/libsysio/tests/test_getcwd.c @@ -0,0 +1,173 @@ +/* + * This Cplant(TM) source code is the property of Sandia National + * Laboratories. + * + * This Cplant(TM) source code is copyrighted by Sandia National + * Laboratories. + * + * The redistribution of this Cplant(TM) source code is subject to the + * terms of the GNU Lesser General Public License + * (see cit/LGPL or http://www.gnu.org/licenses/lgpl.html) + * + * Cplant(TM) Copyright 1998-2003 Sandia Corporation. + * Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive + * license for use of this work by or on behalf of the US Government. + * Export of this program may require a license from the United States + * Government. + */ + +/* + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Questions or comments about this library should be sent to: + * + * Lee Ward + * Sandia National Laboratories, New Mexico + * P.O. Box 5800 + * Albuquerque, NM 87185-1110 + * + * lee@sandia.gov + */ + +#include +#include +#include +#ifndef REDSTORM +#include +#else +#include +#endif +#include +#include +#include +#include +#include +#include + +#include "sysio.h" +#include "mount.h" + +#include "test.h" + +/* + * Test getcwd() + * + * Usage: test_cwd [...] + * + * 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 " + " [ ...\n]"); + + exit(1); +} diff --git a/libsysio/tests/test_getcwd.pl b/libsysio/tests/test_getcwd.pl new file mode 100755 index 0000000..94f33a3 --- /dev/null +++ b/libsysio/tests/test_getcwd.pl @@ -0,0 +1,121 @@ +#!/usr/bin/perl -w + +use IPC::Open2; + +use strict; +use FindBin; +use lib "$FindBin::Bin"; +use helper; +use Fcntl ':mode'; + + +sub usage +{ + print "Usage: ./test_getcwd.pl [-alpha] : Test getcwd by verifying that it \n"; + print " : setting the directory to dir and \n"; + print " : verifying that getcwd reflects \n"; + print " : the change\n"; + exit(-1); +} + +sub check_wkdir +{ + my ($wdir, $outfh, $cmdfh) = @_; + + + # Get cwd from libsysio + my $cmdstr = 'CALL getcwd ( $buf = ALLOC 512 ) 512'."\n"; + helper::send_cmd($cmdfh, $outfh, "getcwd", $cmdstr); + + # Verify the system call's output + helper::verify_cmd($cmdfh, $outfh, "getcwd"); + + # Print out the buffer + $cmdstr = 'PRINT $buf 0 1 STR'."\n"; + helper::send_cmd($cmdfh, $outfh, "PRINT", $cmdstr); + + my $iodir = <$outfh>; + chop($iodir); + + # Only compare the last portion of the working directory + my @iodirs = split(/\//, $iodir); + my @wdirs = split(/\//, $wdir); + + if ($iodirs[-1] ne $wdirs[-1]) { + helper::print_and_exit + ($cmdfh, + $outfh, 0, + "ERROR! topmost wdir ($wdirs[-1]) does not match sysio's ($iodirs[-1])\n"); + } +} + +sub process_cmd +{ + my ($dir, $is_alpha) = @_; + + # Get tests directory + my $testdir = $FindBin::Bin; + + eval { + if ($is_alpha == 0) { + open2(\*OUTFILE, \*CMDFILE, "$testdir/test_driver --np"); + } else { + open2(\*OUTFILE, \*CMDFILE, + "yod -batch -quiet -sz 1 $testdir/test_driver --np"); + } + }; + + if ($@) { + if ($@ =~ /^open2/) { + warn "open2 failed: $!\n$@\n"; + return; + } + die; + + } + + my $outfh = \*OUTFILE; + my $cmdfh = \*CMDFILE; + + if ($is_alpha == 0) { + helper::send_cmd($cmdfh, $outfh, "init", "CALL init\n"); + + # Get current working directory from environment + my $cwd = $ENV{PWD}; + + + } + + # Now change to dir + helper::send_cmd($cmdfh, $outfh, "chdir", "CALL chdir $dir\n"); + + # Verify the system call's output + helper::verify_cmd($cmdfh, $outfh, "PRINT"); + + check_wkdir($dir, $outfh, $cmdfh); + + # Clean up + helper::print_and_exit($cmdfh, $outfh, 0, "getcwd test successful\n"); +} + + +my $currarg = 0; +my $is_alpha = 0; + +if (@ARGV < 1) { + usage; +} elsif (@ARGV > 1) { + if ($ARGV[$currarg++] eq "-alpha") { + $is_alpha = 1; + } +} + +my $dir = $ARGV[$currarg]; + +process_cmd($dir, $is_alpha); + +exit 0; + + + + diff --git a/libsysio/tests/test_link.c b/libsysio/tests/test_link.c new file mode 100644 index 0000000..ab4106f --- /dev/null +++ b/libsysio/tests/test_link.c @@ -0,0 +1,140 @@ +/* + * This Cplant(TM) source code is the property of Sandia National + * Laboratories. + * + * This Cplant(TM) source code is copyrighted by Sandia National + * Laboratories. + * + * The redistribution of this Cplant(TM) source code is subject to the + * terms of the GNU Lesser General Public License + * (see cit/LGPL or http://www.gnu.org/licenses/lgpl.html) + * + * Cplant(TM) Copyright 1998-2003 Sandia Corporation. + * Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive + * license for use of this work by or on behalf of the US Government. + * Export of this program may require a license from the United States + * Government. + */ + +/* + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Questions or comments about this library should be sent to: + * + * Lee Ward + * Sandia National Laboratories, New Mexico + * P.O. Box 5800 + * Albuquerque, NM 87185-1110 + * + * lee@sandia.gov + */ + +#include +#include +#include +#ifndef REDSTORM +#include +#endif +#include +#include +#include +#include +#include +#if 0 +#include +#endif + +#include "sysio.h" +#include "mount.h" + +#include "test.h" + +/* + * Test hard link + * + * Usage: link oldpath newpath + * + */ + +static void usage(void); + +int +main(int argc, char *const argv[]) +{ + int i; + int err; + int n; + extern int _test_sysio_startup(void); + + /* + * Parse command line arguments. + */ + while ((i = getopt(argc, argv, "")) != -1) + switch (i) { + + default: + usage(); + } + + /* + * Init sysio lib. + */ + err = _test_sysio_startup(); + if (err) { + errno = -err; + perror("sysio startup"); + exit(1); + } + + n = argc - optind; + if (n < 2) usage(); + + /* + * Try paths listed on command-line. + */ + while (optind < argc) { + const char *old, *new; + struct stat stbuf; + + old = argv[optind++]; + new = argv[optind++]; + if ((err = link(old, new)) != 0) { + perror("link"); + break; + } + if ((err = lstat(new, &stbuf)) != 0) { + perror(new); + break; + } + } + + /* + * Clean up. + */ + _sysio_shutdown(); + + return err ? -1 : 0; +} + +static void +usage() +{ + + (void )fprintf(stderr, + "Usage: unlink" + " oldpath newpath\n"); + + exit(1); +} diff --git a/libsysio/tests/test_list.c b/libsysio/tests/test_list.c new file mode 100644 index 0000000..4dc0a82 --- /dev/null +++ b/libsysio/tests/test_list.c @@ -0,0 +1,213 @@ +/* + * This Cplant(TM) source code is the property of Sandia National + * Laboratories. + * + * This Cplant(TM) source code is copyrighted by Sandia National + * Laboratories. + * + * The redistribution of this Cplant(TM) source code is subject to the + * terms of the GNU Lesser General Public License + * (see cit/LGPL or http://www.gnu.org/licenses/lgpl.html) + * + * Cplant(TM) Copyright 1998-2003 Sandia Corporation. + * Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive + * license for use of this work by or on behalf of the US Government. + * Export of this program may require a license from the United States + * Government. + */ + +/* + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Questions or comments about this library should be sent to: + * + * Lee Ward + * Sandia National Laboratories, New Mexico + * P.O. Box 5800 + * Albuquerque, NM 87185-1110 + * + * lee@sandia.gov + */ + +#include +#include +#include +#ifndef REDSTORM +#include +#else +#include +#endif +#include +#include +#include +#include +#include +#include + +#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" + " [ ...\n]"); + + exit(1); +} diff --git a/libsysio/tests/test_list.pl b/libsysio/tests/test_list.pl new file mode 100755 index 0000000..5be13d2 --- /dev/null +++ b/libsysio/tests/test_list.pl @@ -0,0 +1,237 @@ +#!/usr/bin/perl -w + +# +# getdirentries test: Tests the equivalent of a ls. Note that this is not +# the most robust test in the world; it simply verifies +# that libsysio returns all the entries in the directory +# +# + +use IPC::Open2; + +use strict; + +use FindBin; +use lib "$FindBin::Bin"; +use helper; + +sub usage +{ + print "Usage: ./test_list.pl [-p|-alpha] \n"; + print " ./test_list.pl -m [-p|-alpha] fstype:mdir dir\n"; + print " In the first form, will attempt to verify libsysio's\n"; + print " getdirentries. If no dir is given, will use the \n"; + print " current working directory\n"; + print " In the second form, will mount the given mdir (of type fstype) in dir.\n"; + print " It will then verify the output of libsysio's getdirentries. It will \n"; + print " then umount the directory and verify that the umount worked\n"; + print " The -p option will print the directory listing\n"; + print " The -alpha option is for alpha architecture \n"; + exit(-1); +} + + +sub write_print +{ + my ($offset, $outfh, $cmdfh, $do_print, $is_alpha) = @_; + my $bytes = 0; + + my $intsize = 8; + my $intcmd = "INT"; + if ($is_alpha == 1) { + $intsize = 16; + $intcmd = "LONG" + } + my $shortoffset = $offset+$intsize; + my $charoffset = $shortoffset+2; + my $stroffset = $charoffset+1; + my $cmdstr = 'PRINT $buf '. + "$offset $intsize $intcmd $shortoffset 2 SHORT $charoffset 1 CHAR $stroffset 1 STR\n"; + helper::send_cmd($cmdfh, $outfh, "PRINT", $cmdstr); + + my $res = <$outfh>; + chop($res); + my ($inode, $foffset, $size, $type, @names) = split(' ',$res); + $size = oct($size); + if ($size == 0) { + return -1; + } + my $name = join(' ', @names); + + if ($do_print == 1) { + printf(STDOUT "%-35s %-14s %-14s %-6s %-4s\n", $name, $inode, $foffset, $size, $type); + } + + return $size; +} + +sub do_print_cmds +{ + my ($numbytes, $outfh, $cmdfh, $start, $do_print, $is_alpha) = @_; + + my $offset = 0; + my $bytes = 0; + my $numfiles = 0; + my $i = $start; + + if ($numbytes == 0) { + $numbytes = 8192; + } + while ($bytes < $numbytes) { + my $len = write_print($offset, $outfh, $cmdfh, $do_print, $is_alpha); + if ($len <= 0) { + # write_print saw a 0 length record, indicating end of dir + return $numfiles; + } + $numfiles++; + if ($is_alpha == 0) { + $len += $len%4; + } else { + $len += $len%8; + } + $offset += $len; + $bytes += $len; + $i++; + } + return $numfiles; +} + +sub print_dir_cmd +{ + + my ($outfh, $cmdfh, $start, $mdir, $do_print, $is_alpha) = @_; + + my $cmdstr = "CALL getdirentries ( ".'$fd = CALL open '."$mdir O_RDONLY ) ( "; + $cmdstr .= '$buf = ALLOC 8192 ) 8192 $basep'."\n"; + helper::send_cmd($cmdfh, $outfh, "getdirentries", $cmdstr); + + # Verify that the sysio call succeeded + my $res = helper::verify_cmd($cmdfh, $outfh, "getdirentries"); + my $numbytes = oct($res); + + while ($numbytes > 0) { + + do_print_cmds($numbytes, $outfh, $cmdfh, $start, $do_print, $is_alpha); + + $cmdstr = "CALL getdirentries ".'$fd $buf 8192 $basep'."\n"; + helper::send_cmd($cmdfh, $outfh, "getdirentries", $cmdstr); + + # Verify that the sysio call succeeded + my $res = helper::verify_cmd($cmdfh, $outfh, "getdirentries"); + $numbytes = oct($res); + } +} + +sub process_cmd +{ + my ($mdir, $tdir, $do_mount, $is_alpha, $do_print) = @_; + my $size = 8192; + my $done_files = 0; + + # Get tests directory + my $testdir = $FindBin::Bin; + + eval { + if ($is_alpha == 1) { + open2(\*OUTFILE, \*CMDFILE, "yod -quiet -sz 1 $testdir/test_driver --np"); + } else { + open2(\*OUTFILE, \*CMDFILE, "$testdir/test_driver --np"); + } + }; + + if ($@) { + if ($@ =~ /^open2/) { + warn "open2 failed: $!\n$@\n"; + return; + } + die; + + } + + my $outfh = \*OUTFILE; + my $cmdfh = \*CMDFILE; + + if ($is_alpha == 0) { + helper::send_cmd($cmdfh, $outfh, "init", "CALL init\n"); + } + + my $start = 0; + + if ($do_mount == 1) { + helper::send_cmd($cmdfh, $outfh, "mount", "CALL mount $mdir $tdir\n"); + print_dir_cmd($outfh, $cmdfh, $start, $tdir, $do_print, $is_alpha); + } else { + print_dir_cmd($outfh, $cmdfh, $start, $mdir, $do_print, $is_alpha); + } + + # Attempt to unmount and verify the contents + if ($do_mount == 1) { + + # Close the dir before we umount + my $cmdstr = 'CALL close $fd'."\n"; + helper::send_cmd($cmdfh, $outfh, "close", $cmdstr); + + # umount dir + helper::send_cmd($cmdfh, $outfh, "umount", "CALL umount $tdir\n"); + + + # Verify it is umounted + $cmdstr = "CALL getdirentries ( ".'$fd2 = CALL open '."$tdir O_RDONLY ) "; + $cmdstr .= '$buf 8192 $newp'."\n"; + helper::send_cmd($cmdfh, $outfh, "getdirentries", $cmdstr); + my $res = helper::verify_cmd($cmdfh, $outfh, "getdirentries"); + + my $numbytes = oct($res); + # The only entries should be . and .., so should return 32 + if ($numbytes != 32) { + helper::print_and_exit($cmdfh, $outfh, 1, "ERROR! Read in $numbytes bytes\n"); + } + # Clean up + $cmdstr = 'CALL close $fd2'."\n"; + helper::send_cmd($cmdfh, $outfh, "close", $cmdstr); + + } else { + my $cmdstr = 'CALL close $fd'."\n"; + helper::send_cmd($cmdfh, $outfh, "getdirentries", $cmdstr); + } + + helper::print_and_exit($cmdfh, $outfh, 0, "list test successful\n"); +} + + +# Default dir is cwd +my @mydir; +$mydir[0] = "./"; +my $do_mount = 0; +my $is_alpha = 0; +my $do_print = 0; +my $dircnt = 0; +for (my $i = 0; $i < @ARGV; $i++) +{ + if ($ARGV[$i] eq "-p") { + $do_print = 1; + } elsif ($ARGV[$i] eq "-m") { + $do_mount = 1; + } elsif ($ARGV[$i] eq "-alpha") { + $is_alpha = 1; + } else { + $mydir[$dircnt] = $ARGV[$i]; + $dircnt++; + } +} + +if ( ($dircnt == 0) || ($dircnt > 2) || + (($do_mount==1) && ($dircnt < 2)) || + (($do_mount == 0) && ($dircnt > 1)) ) { + usage(); +} + +my $dir = $mydir[0]; +if ($do_mount == 1) { + my $fstype; + ($fstype, $dir) = split(/:/, $mydir[0]); +} + +process_cmd($mydir[0], $mydir[1], $do_mount, $is_alpha, $do_print); + +exit 0; diff --git a/libsysio/tests/test_path.c b/libsysio/tests/test_path.c new file mode 100644 index 0000000..a7469b3 --- /dev/null +++ b/libsysio/tests/test_path.c @@ -0,0 +1,229 @@ +/* + * This Cplant(TM) source code is the property of Sandia National + * Laboratories. + * + * This Cplant(TM) source code is copyrighted by Sandia National + * Laboratories. + * + * The redistribution of this Cplant(TM) source code is subject to the + * terms of the GNU Lesser General Public License + * (see cit/LGPL or http://www.gnu.org/licenses/lgpl.html) + * + * Cplant(TM) Copyright 1998-2003 Sandia Corporation. + * Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive + * license for use of this work by or on behalf of the US Government. + * Export of this program may require a license from the United States + * Government. + */ + +/* + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Questions or comments about this library should be sent to: + * + * Lee Ward + * Sandia National Laboratories, New Mexico + * P.O. Box 5800 + * Albuquerque, NM 87185-1110 + * + * lee@sandia.gov + */ + +#include +#include +#include +#ifndef REDSTORM +#include +#else +#include +#endif +#include + +#include +#include +#include +#include + +#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" + " [ ...\n]"); + + exit(1); +} diff --git a/libsysio/tests/test_path.pl b/libsysio/tests/test_path.pl new file mode 100755 index 0000000..c68fdc8 --- /dev/null +++ b/libsysio/tests/test_path.pl @@ -0,0 +1,188 @@ +#!/usr/bin/perl -w + +# +# path test: reads paths from stdin and prints out the path along with its +# : type +# + +use IPC::Open2; + +use strict; +use FindBin; +use lib "$FindBin::Bin"; +use helper; +use POSIX; +use Fcntl ':mode'; + +sub usage +{ + print "Usage ./test_path.pl [path1 path2...] : Print each path listed and its type\n"; + print " : If no paths are given, stdin is read\n"; + exit(-1); +} + +sub get_type +{ + my $mode = $_[0]; + my $t = '?'; + + if (S_ISDIR($mode)) { + $t = 'd'; + } elsif (S_ISCHR($mode)) { + $t = 'c'; + } elsif (S_ISBLK($mode)) { + $t = 'b'; + } elsif (S_ISREG($mode)) { + $t = 'f'; + } elsif (S_ISFIFO($mode)) { + $t = 'p'; + } elsif (S_ISLNK($mode)) { + $t = 'S'; + } elsif (S_ISSOCK($mode)) { + $t = 's'; + } + + return $t; +} + +sub print_path +{ + my ($mode, $path) = @_; + + my $typechar = get_type($mode); + print STDOUT "$path: $typechar\n"; +} + +sub process_path +{ + my ($cmdfh, $outfh, $bits, $path) = @_; + + # Issue the stat command + my $cmdstr = 'CALL stat "'; + $cmdstr = sprintf("%s%s%s\n", $cmdstr, $path, '" $buf'); + + helper::send_cmd($cmdfh, $outfh, "stat", $cmdstr); + helper::verify_cmd($cmdfh, $outfh, "stat"); + + # Print out the stat buffer + if ($bits == 32) { + $cmdstr = 'PRINT $buf 0 8 LONG 12 24 INT 44 8 LONG 52 8 INT 64 24 LONG'; + } else { + $cmdstr = 'PRINT $buf 0 24 LONG 24 16 INT 48 32 LONG 88 8 LONG 104 8 LONG'; + } + $cmdstr .= "\n"; + helper::send_cmd($cmdfh, $outfh, "PRINT", $cmdstr); + + my $res = <$outfh>; + chop($res); + my ( $iodev, $ioino, $iomode, $ionlink, $iouid, $iogid, $iordev, + $iosize, $ioblksize, $ioblks, $ioatime, $iomtime, $ioctime ) + = split(' ', $res); + if ($bits == 64) { + ( $iodev, $ioino, $ionlink, $iomode, $iouid, $iogid, $iordev, + $iosize, $ioblksize, $ioblks, $ioatime, $iomtime, $ioctime ) + = split(' ', $res); + } + $iomode = oct($iomode); + + # Print out the path + print_path($iomode, $path); +} + +sub process_cmd +{ + my ($usestdin, $isalpha, @paths) = @_; + + my $path; + + # Get tests directory + my $testdir = $FindBin::Bin; + + eval { + if ($isalpha == 0) { + open2(\*OUTFILE, \*CMDFILE, "$testdir/test_driver --np"); + } else { + open2(\*OUTFILE, \*CMDFILE, + "yod -batch -quiet -sz 1 $testdir/test_driver --np"); + } + }; + + if ($@) { + if ($@ =~ /^open2/) { + warn "open2 failed: $!\n$@\n"; + return; + } + die; + + } + my $outfh = \*OUTFILE; + my $cmdfh = \*CMDFILE; + + if ($isalpha == 0) { + helper::send_cmd($cmdfh, $outfh, "init", "CALL init\n"); + } + + # Allocate the stat buffer + my $cmdstr = '$buf = ALLOC ( $size = CALL sizeof stat )'; + $cmdstr .= "\n"; + helper::send_cmd($cmdfh, $outfh, "alloc", $cmdstr); + + # Attempt to determine type + $cmdstr = 'PRINT $size'."\n"; + helper::send_cmd($cmdfh, $outfh, "print", $cmdstr); + my $statsize = <$outfh>; + chop($statsize); + $statsize = oct($statsize); + my $bits = 32; + if ($statsize == 144) { + $bits = 64; + } + + my $i=0; + if ($usestdin) { + $path = ; + 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 = ; + + if (defined($path)) { + chop($path); + } + if ($path eq "quit") { + helper::print_and_exit($cmdfh, $outfh, 0, "path test successful\n"); + } + } else { + $path = $paths[$i++]; + } + } + helper::print_and_exit($cmdfh, $outfh, 0, "path test successful\n"); +} + + +my $usestdin = 0; +my $isalpha = 0; + +# The -alpha arg must be before the paths +# (if they exist) +if ( (@ARGV > 0) && ($ARGV[0] eq "-alpha")) { + $isalpha = 1; + shift(@ARGV); +} + +if (@ARGV == 0) { + $usestdin = 1; +} + +process_cmd($usestdin, $isalpha, @ARGV); + diff --git a/libsysio/tests/test_regions.c b/libsysio/tests/test_regions.c new file mode 100644 index 0000000..c6120da --- /dev/null +++ b/libsysio/tests/test_regions.c @@ -0,0 +1,297 @@ +/* + * This Cplant(TM) source code is the property of Sandia National + * Laboratories. + * + * This Cplant(TM) source code is regionsrighted by Sandia National + * Laboratories. + * + * The redistribution of this Cplant(TM) source code is subject to the + * terms of the GNU Lesser General Public License + * (see cit/LGPL or http://www.gnu.org/licenses/lgpl.html) + * + * Cplant(TM) Copyright 1998-2004 Sandia Corporation. + * Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive + * license for use of this work by or on behalf of the US Government. + * Export of this program may require a license from the United States + * Government. + */ + +/* + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a regions of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Questions or comments about this library should be sent to: + * + * Lee Ward + * Sandia National Laboratories, New Mexico + * P.O. Box 5800 + * Albuquerque, NM 87185-1110 + * + * lee@sandia.gov + */ + +#define _BSD_SOURCE + +#if (_LARGEFILE64_SOURCE && \ + ((defined(__STDC_VERSION__) && __STDC_VERSION__ == 199901L))) +#define GO64 +#else +#warning Cannot prompt the 64-bit interface +#endif + +#if defined(GO64) && defined(__GLIBC__) +#define _ISOC99_SOURCE 1 +#endif + +#include +#include +#include +#include +#ifndef REDSTORM +#include +#endif +#include +#include +#include +#include +#include +#include + +#include "sysio.h" +#include "mount.h" + +#include "test.h" + +/* + * Copy one file to another. + * + * Usage: test_regions [-x] \ + * {r,w} + * + * 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} \n"); + exit(1); +} diff --git a/libsysio/tests/test_rename.c b/libsysio/tests/test_rename.c new file mode 100644 index 0000000..7b78429 --- /dev/null +++ b/libsysio/tests/test_rename.c @@ -0,0 +1,137 @@ +/* + * This Cplant(TM) source code is the property of Sandia National + * Laboratories. + * + * This Cplant(TM) source code is copyrighted by Sandia National + * Laboratories. + * + * The redistribution of this Cplant(TM) source code is subject to the + * terms of the GNU Lesser General Public License + * (see cit/LGPL or http://www.gnu.org/licenses/lgpl.html) + * + * Cplant(TM) Copyright 1998-2003 Sandia Corporation. + * Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive + * license for use of this work by or on behalf of the US Government. + * Export of this program may require a license from the United States + * Government. + */ + +/* + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Questions or comments about this library should be sent to: + * + * Lee Ward + * Sandia National Laboratories, New Mexico + * P.O. Box 5800 + * Albuquerque, NM 87185-1110 + * + * lee@sandia.gov + */ + +#define _BSD_SOURCE + +#include +#include +#include +#ifndef REDSTORM +#include +#endif +#include +#include +#include +#include +#include + +#include "sysio.h" +#include "mount.h" + +#include "fs_native.h" + +#include "test.h" + +/* + * Rename a file system object. + * + * Usage: test_rename + */ + +void usage(void); +int rename_file(const char *spath, const char *dpath); + +int +main(int argc, char * const argv[]) +{ + int i; + int err; + const char *spath, *dpath; + extern int _test_sysio_startup(void); + + /* + * Parse command-line args. + */ + while ((i = getopt(argc, + argv, + "" + )) != -1) + switch (i) { + + default: + usage(); + } + + if (!(argc - optind)) + usage(); + + err = _test_sysio_startup(); + if (err) { + errno = -err; + perror("sysio startup"); + exit(1); + } + + (void )umask(022); + + /* + * Source + */ + spath = argv[optind++]; + if (!(argc - optind)) + usage(); + /* + * Destination + */ + dpath = argv[optind++]; + if (argc - optind) + usage(); + + err = rename(spath, dpath); + if (err) + perror("rename"); + + _sysio_shutdown(); + + return err; +} + +void +usage() +{ + + (void )fprintf(stderr, + "Usage: test_rename" + " source destination\n"); + exit(1); +} diff --git a/libsysio/tests/test_rw.pl b/libsysio/tests/test_rw.pl new file mode 100755 index 0000000..74a7fa0 --- /dev/null +++ b/libsysio/tests/test_rw.pl @@ -0,0 +1,537 @@ +#!/usr/bin/perl -w + +# +# rw test: Write a buffer out using all the different writes, read it back +# and make sure it matches +# +# + +use IPC::Open2; + +use strict; +use FindBin; +use lib "$FindBin::Bin"; +use helper; + +sub usage +{ + print "Usage: ./test_rw.pl [-alpha] : 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, ") { + if (/^\*/) { + # Do nothing... + } else { + my ($lineno, @nums) = split($_); + if (check_array($exp_digit, @nums) != 0) { + helper::print_and_exit($cmdfh, $outfh, 1, "At line $lineno, got unexpected result\n"); + } + if ($exp_digit < 9) { + $exp_digit ++; + } else { + $exp_digit = 0; + } + } + } + + close(ODFILE); + system("rm -f tmp.out.$$"); +} + +sub process_cmd +{ + my ($file, $is_alpha) = @_; + + # Get tests directory + my $testdir = $FindBin::Bin; + my $bufsize = 65536; + + eval { + if ($is_alpha == 0) { + open2(\*OUTFILE, \*CMDFILE, "$testdir/test_driver --np"); + } else { + open2(\*OUTFILE, \*CMDFILE, "yod -quiet -sz 1 $testdir/test_driver --np"); + } + }; + + if ($@) { + if ($@ =~ /^open2/) { + warn "open2 failed: $!\n$@\n"; + return; + } + die; + + } + + my $outfh = \*OUTFILE; + my $cmdfh = \*CMDFILE; + + if ($is_alpha == 0) { + helper::send_cmd($cmdfh, $outfh, "init", "CALL init\n"); + } + + # Open file + my $cmdstr = '$fd = CALL open '."$file O_RDWR|O_CREAT 0777\n"; + helper::send_cmd($cmdfh, $outfh, "open", $cmdstr); + helper::verify_cmd($cmdfh, $outfh, $cmdstr); + + + # Allocate buffer + $cmdstr = '$buf = ALLOC '."$bufsize\n"; + helper::send_cmd($cmdfh, $outfh, "ALLOC", $cmdstr); + + + do_rwcalls($cmdfh, $outfh, $bufsize); + + # Clean up + $cmdstr = 'CALL close $fd'."\n"; + helper::send_cmd($cmdfh, $outfh, "close", $cmdstr); + + # Verify it worked + od_verify($cmdfh, $outfh, $file); + + system("rm -f $file"); + helper::print_and_exit($cmdfh, $outfh, 0, "rw test successful\n"); +} + +my $currarg = 0; +my $is_alpha = 0; + +if (@ARGV < 1) { + usage; +} elsif (@ARGV > 1 ) { + if ($ARGV[$currarg++] eq "-alpha") { + $is_alpha = 1; + } +} + +my $file = $ARGV[$currarg]; + +process_cmd($file, $is_alpha); + + +exit 0; diff --git a/libsysio/tests/test_stats.c b/libsysio/tests/test_stats.c new file mode 100644 index 0000000..2865a02 --- /dev/null +++ b/libsysio/tests/test_stats.c @@ -0,0 +1,192 @@ +/* + * This Cplant(TM) source code is the property of Sandia National + * Laboratories. + * + * This Cplant(TM) source code is copyrighted by Sandia National + * Laboratories. + * + * The redistribution of this Cplant(TM) source code is subject to the + * terms of the GNU Lesser General Public License + * (see cit/LGPL or http://www.gnu.org/licenses/lgpl.html) + * + * Cplant(TM) Copyright 1998-2003 Sandia Corporation. + * Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive + * license for use of this work by or on behalf of the US Government. + * Export of this program may require a license from the United States + * Government. + */ + +/* + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Questions or comments about this library should be sent to: + * + * Lee Ward + * Sandia National Laboratories, New Mexico + * P.O. Box 5800 + * Albuquerque, NM 87185-1110 + * + * lee@sandia.gov + */ + +#define _BSD_SOURCE + +#include +#include +#include +#ifndef REDSTORM +#include +#endif +#include +#include +#include +#include +#include +#ifdef notdef +#include +#endif + +#include "sysio.h" +#include "mount.h" + +#include "test.h" + +/* + * Get stats of file and file system. + * + * Usage: test_stats [ ...] + */ + +void usage(void); +void do_stats(const char *path); + +int +main(int argc, char * const argv[]) +{ + int i; + int err; + extern int _test_sysio_startup(void); + + /* + * Parse command-line args. + */ + while ((i = getopt(argc, argv, "")) != -1) + switch (i) { + + default: + usage(); + } + + err = _test_sysio_startup(); + if (err) { + errno = -err; + perror("sysio startup"); + exit(1); + } + + (void )umask(022); + + while (optind < argc) + do_stats(argv[optind++]); + + /* + * Clean up. + */ + _sysio_shutdown(); + + return 0; +} + +void +usage() +{ + + (void )fprintf(stderr, + "Usage: test_stats" + " source destination\n"); + exit(1); +} + +void +do_stats(const char *path) +{ + int fd; + int err; + struct stat stbuf1, stbuf2; +#ifdef notdef + struct statvfs stvfsbuf1, stvfsbuf2; +#endif + + fd = open(path, O_RDONLY); + if (fd < 0) { + perror(path); + return; + } + err = fstat(fd, &stbuf1); + if (!err) + err = stat(path, &stbuf2); +#ifdef notdef + if (!err) + err = fstatvfs(fd, &stvfsbuf1); + if (!err) + err = statvfs(path, &stvfsbuf1); +#endif + if (err) { + perror(path); + goto out; + } + if (stbuf1.st_dev != stbuf2.st_dev || + stbuf1.st_ino != stbuf2.st_ino) { + (void )fprintf(stderr, "%s: [f]stat info mismatch\n", path); + goto out; + } +#ifdef notdef + if (stvfsbuf1.f_fsid != stvfsbuf2.f_fsid) { + (void )fprintf(stderr, "%s: [f]statvfs info mismatch\n", path); + } +#endif + printf("%s:" + " dev %lu," + " ino %lu," + " mode %lu," + " nlink %lu," + " uid %lu," + " gid %lu," + " rdev %lu," + " size %llu," + " blksize %lu," + " blocks %lu," + " atime %lu," + " mtime %lu," + " ctime %lu" + "\n", + path, + (unsigned long )stbuf1.st_dev, + (unsigned long )stbuf1.st_ino, + (unsigned long )stbuf1.st_mode, + (unsigned long )stbuf1.st_nlink, + (unsigned long )stbuf1.st_uid, + (unsigned long )stbuf1.st_gid, + (unsigned long )stbuf1.st_rdev, + (unsigned long long)stbuf1.st_size, + (unsigned long )stbuf1.st_blksize, + (unsigned long )stbuf1.st_blocks, + (unsigned long )stbuf1.st_atime, + (unsigned long )stbuf1.st_mtime, + (unsigned long )stbuf1.st_ctime); +out: + if (close(fd) != 0) + perror("closing file"); +} diff --git a/libsysio/tests/test_stats.pl b/libsysio/tests/test_stats.pl new file mode 100755 index 0000000..fee6a32 --- /dev/null +++ b/libsysio/tests/test_stats.pl @@ -0,0 +1,268 @@ +#!/usr/bin/perl -w + +# +# stats test: Verifies that the set of stat calls (stat, fstat, fstatvfs, and +# statvfs) return the same items and that the calls return the +# same items as Perl's stat call (which would use a native library +# and not libsysio) +# +# + +use IPC::Open2; + +use strict; +use FindBin; +use lib "$FindBin::Bin"; +use helper; + +sub usage +{ + print "Usage ./test_stats.pl file : Verifies that the set of stat calls (stat, \n"; + print " : fstat, fstatvfs, statvfs) return the same set\n"; + print " : of stats for file and that the calls return \n"; + print " : the same items as Perl's stat call (which \n"; + print " : would use a native library and not libsysio)\n"; + exit(-1); +} + +# Compares the output of Perl's stat function with the output +# from libsysio's stat +sub cmp_stats +{ + + my ( $cmdfh, $outfh, $is_alpha, $bits, @stats) = @_; + + + my ($iodev, $ioino, $iomode, $ionlink, $iouid, $iogid, $iordev, + $iosize, $ioblksize, $ioblks, $ioatime, $iomtime, $ioctime, @pstats) = + @stats; + + if ($is_alpha == 1) { + ($iodev, $ioino, $iomode, $ionlink, $iouid, $iogid, $iordev, + $iosize, $ioatime, $iomtime, $ioctime, $ioblks, $ioblksize, @pstats) = + @stats; + } + if ($bits == 64) { + ($iodev, $ioino, $ionlink, $iomode, $iouid, $iogid, $iordev, + $iosize, $ioblksize, $ioblks, $ioatime, $iomtime, $ioctime,@pstats) = + @stats; + } + my ($pdev, $pino, $pmode, $pnlink, $puid, $pgid, $prdev, + $psize, $patime, $pmtime, $pctime, $pblksize, $pblks) = @pstats; + +# helper::cmp_nums($cmdfh, $outfh, $iodev, $pdev, "device numbers"); + helper::cmp_nums($cmdfh, $outfh, $ioino, $pino, "inode numbers"); + helper::cmp_nums($cmdfh, $outfh, $iomode, $pmode, "file modes"); + helper::cmp_nums($cmdfh, $outfh, $ionlink, $pnlink, "number of links"); + helper::cmp_nums($cmdfh, $outfh, $iouid, $puid, "user ids"); + helper::cmp_nums($cmdfh, $outfh, $iogid, $pgid, "group ids"); + helper::cmp_nums($cmdfh, $outfh, $iordev, $prdev, "device ids"); + helper::cmp_nums($cmdfh, $outfh, $iosize, $psize, "file sizes"); + helper::cmp_nums($cmdfh, $outfh, $ioatime, $patime, "access times"); + helper::cmp_nums($cmdfh, $outfh, $iomtime, $pmtime, "modification times"); + helper::cmp_nums($cmdfh, $outfh, $ioctime, $pctime, "inode change times"); + helper::cmp_nums($cmdfh, $outfh, $ioblksize, $pblksize, "block sizes"); + helper::cmp_nums($cmdfh, $outfh, $ioblks, $pblks, "blocks allocated"); +} + + +# Prints out the stat buffer and verifies that it matches +# Perl's output +sub verify_stat +{ + my ($cmdfh, $outfh, $cmd, $is_alpha, $bits, @stats) = @_; + my $i=0; + + my $cmdstr; + # Print out the stat buffer + if ($is_alpha == 1) { + $cmdstr = 'PRINT $buf 0 16 LONG 16 16 INT 32 8 LONG 40 4 INT 48 40 LONG'."\n"; + } elsif ($bits == 32) { + $cmdstr = 'PRINT $buf 0 8 LONG 12 24 INT 44 8 LONG 48 8 INT 56 24 LONG'."\n"; + } else { + $cmdstr = 'PRINT $buf 0 24 LONG 24 16 INT 48 32 LONG 88 8 LONG 104 8 LONG'."\n"; + } + + helper::send_cmd($cmdfh, $outfh, "PRINT", $cmdstr); + + my $res = <$outfh>; + chop($res); + + my @iostats = split(' ', $res); + foreach my $iostat (@iostats) { + $iostats[$i] = oct($iostat); + $i++; + } + + cmp_stats($cmdfh, $outfh, $is_alpha, $bits, @iostats, @stats); + +} + +sub process_cmd +{ + my ($file, $use_system, $is_alpha) = @_; + +# Get tests directory + my $testdir = $FindBin::Bin; + + eval { + if ($is_alpha == 0) { + open2(\*OUTFILE, \*CMDFILE, "$testdir/test_driver --np"); + } else { + open2(\*OUTFILE, \*CMDFILE, + "yod -batch -quiet -sz 1 $testdir/test_driver --np"); + } + }; + + if ($@) { + if ($@ =~ /^open2/) { + warn "open2 failed: $!\n$@\n"; + return; + } + die; + + } + + my $outfh = \*OUTFILE; + my $cmdfh = \*CMDFILE; + + if ($is_alpha == 0) { + helper::send_cmd($cmdfh, $outfh, "init", "CALL init\n"); + } + + my @stats; + if ($use_system == 1) { + # Get stats for file + @stats = stat($file); + } + + # Allocate the buffer + my $cmdstr = '$buf = ALLOC ( $size = CALL sizeof stat )'."\n"; + helper::send_cmd($cmdfh, $outfh, "alloc", $cmdstr); + + + # Issue the stat command + $cmdstr = 'CALL stat '."$file ".'$buf'."\n"; + helper::send_cmd($cmdfh, $outfh, "stat", $cmdstr); + helper::verify_cmd($cmdfh, $outfh, "stat"); + + # Attempt to determine type + $cmdstr = 'PRINT $size'."\n"; + helper::send_cmd($cmdfh, $outfh, "print", $cmdstr); + my $statsize = <$outfh>; + chop($statsize); + $statsize = oct($statsize); + my $bits = 32; + if ($statsize == 144) { + $bits = 64; + } + + if ($use_system == 1) { + # Now print the buffer out and verify that it matches + # what Perl has + verify_stat($cmdfh, $outfh, "stat", $is_alpha, $bits, @stats); + } + + # Open the file + $cmdstr = '$fd = CALL open '."$file O_RDONLY\n"; + helper::send_cmd($cmdfh, $outfh, "open", $cmdstr); + helper::verify_cmd($cmdfh, $outfh, "open"); + + + # Now issue an fstat call + $cmdstr = 'CALL fstat $fd $buf'."\n"; + helper::send_cmd($cmdfh, $outfh, "fstat", $cmdstr); + helper::verify_cmd($cmdfh, $outfh, "fstat"); + + if ($use_system == 1) { + verify_stat($cmdfh, $outfh, "fstat", $is_alpha, $bits, @stats); + } + + # Test lstat + if ($use_system == 1) { + @stats = lstat($file); + } + + $cmdstr = 'CALL lstat '."$file ".'$buf'."\n"; + helper::send_cmd($cmdfh, $outfh, "lstat", $cmdstr); + helper::verify_cmd($cmdfh, $outfh, "lstat"); + + if ($use_system == 1) { + verify_stat($cmdfh, $outfh, "lstat", $is_alpha, $bits, @stats); + } + + if (0) { + # Now do statvfs functions + $cmdstr = '$buf2 = ALLOC ( $size2 = CALL sizeof statvfs )'."\n"; + helper::send_cmd($cmdfh, $outfh, "alloc", $cmdstr); + + # Clear out the buffer + $cmdstr = 'CALL clear $buf2'."\n"; + helper::send_cmd($cmdfh, $outfh, "CLEAR", $cmdstr); + + $cmdstr = 'CALL statvfs '."$file ".'$buf2'."\n"; + helper::send_cmd($cmdfh, $outfh, "statvfs", $cmdstr); + helper::verify_cmd($cmdfh, $outfh, "statvfs"); + + # Print out the statvfs buffer + $cmdstr = 'PRINT $buf2 0 16 LONG 16 32 INT 48 16 LONG'."\n"; + helper::send_cmd($cmdfh, $outfh, "PRINT", $cmdstr); + + my $res = <$outfh>; + chop($res); + my @vfsstats1 = split(' ', $res); + + # Clear out the buffer + $cmdstr = 'CALL clear $buf2'."\n"; + helper::send_cmd($cmdfh, $outfh, "CLEAR", $cmdstr); + + # Now do fstatvfs + $cmdstr = 'CALL fstatvfs $fd $buf2'."\n"; + helper::send_cmd($cmdfh, $outfh, "fstatvfs", $cmdstr); + helper::verify_cmd($cmdfh, $outfh, "fstatvfs"); + + # Print out the statvfs buffer + $cmdstr = 'PRINT $buf2 0 16 LONG 16 32 INT 48 16 LONG'."\n"; + helper::send_cmd($cmdfh, $outfh, "PRINT", $cmdstr); + + $res = <$outfh>; + chop($res); + my @vfsstats2 = split(' ', $res); + + # Verify the two vfsstats arrays match + if (@vfsstats1 != @vfsstats2) { + helper::print_and_exit($cmdfh, $outfh, 1, "Two vfsstat arrays unequal lengths\n"); + } + + my $i=0; + + foreach my $stat1 (@vfsstats1) { + if ($stat1 ne $vfsstats2[$i++]) { + my $str = sprintf("vfsstats field %d are not equal (%s != %s)\n", + $i-1, $stat1, $vfsstats2[$i-1]); + helper::print_and_exit($cmdfh, $outfh, 1, $str); + } + } + } + + helper::print_and_exit($cmdfh, $outfh, 0, "stat test successful\n"); +} + + + + +my $currarg = 0; +my $is_alpha = 0; +if (@ARGV < 2) { + usage; +} elsif (@ARGV > 2) { + if ($ARGV[$currarg++] eq "-alpha") { + $is_alpha = 1; + } +} + +my $use_system= $ARGV[$currarg++]; +my $file = $ARGV[$currarg]; + +process_cmd($file, $use_system, $is_alpha); + diff --git a/libsysio/tests/test_stdfd.pl b/libsysio/tests/test_stdfd.pl new file mode 100755 index 0000000..afd5548 --- /dev/null +++ b/libsysio/tests/test_stdfd.pl @@ -0,0 +1,242 @@ +#!/usr/bin/perl -w + +# +# stdfd test: Verifies that stdin, stdout, and stderr can be opened and +# either written to or read from (in the case of stdin) + +use IPC::Open2; + +use strict; +use FindBin; +use lib "$FindBin::Bin"; +use helper; + +sub usage +{ + print "Usage ./test_stdfd : Verifies that stdin, stdout, and stderr can be opened and "; + print " : either written to or read from (in the case of stdin)"; + exit(-1); +} + +sub mkdev +{ + my ($major, $minor) = @_; + my $devno = ( (($major & 0xff) << 8) | ($minor & 0xff) ); + + return $devno; +} + +sub statit +{ + my ($cmdfh, $outfh, $do_print, $name) = @_; + + my $cmd = "CALL stat $name ".'$buf'."\n"; + + helper::send_cmd($cmdfh, $outfh, "stat", $cmd); + helper::verify_cmd($cmdfh, $outfh, "stat $name"); + + # Print out the stat buffer + $cmd = 'PRINT $buf 0 8 LONG 12 24 INT 44 8 LONG 52 8 INT 64 24 LONG'; + $cmd .= "\n"; + helper::send_cmd($cmdfh, $outfh, "PRINT", $cmd); + + my $res = <$outfh>; + chop($res); + my ( $iodev, $ioino, $iomode, $ionlink, $iouid, $iogid, $iordev, + $iosize, $ioblksize, $ioblks, $ioatime, $iomtime, $ioctime ) + = split(' ', $res); + + $iomode = oct($iomode); + + if ($do_print == 1) { + # Print out the path + my $typechar = helper::get_type($iomode); + print STDOUT "$name: $typechar\n"; + } + return 0; +} + +sub do_open +{ + + my ($cmdfh, $outfh, $name, $mode, $num) = @_; + + helper::send_cmd($cmdfh, $outfh, "open", "CALL open $name $mode\n"); + + my $res = helper::verify_cmd($cmdfh, $outfh, "open $name"); + + #chop($res); + $res = oct($res); + if ($res < 0) { + helper::print_and_exit($cmdfh, $outfh, 1, "Unable to open $name\n"); + } + + + if ($res == $num) { + return $res; + } + + helper::send_cmd($cmdfh, $outfh, "dup2", "CALL dup2 $res $num\n"); + $res = helper::verify_cmd($cmdfh, $outfh, "dup2"); + $res = oct($res); + + if ($res != $num) { + helper::print_and_exit($cmdfh, $outfh, 1, "Unable to dup $name (res was $res)\n"); + } +} + +sub do_mknod +{ + + my ($cmdfh, $outfh, $do_print, $name, $perm_num, $minor) = @_; + + my $perm = 'S_IFCHR|'.$perm_num; + my $devno = mkdev(0, $minor); + + helper::send_cmd($cmdfh, $outfh, "mknod", "CALL mknod $name $perm $devno\n"); + + helper::verify_cmd($cmdfh, $outfh, "mknod $name"); + + my $statres = statit($cmdfh, $outfh, $do_print, $name); + if ($statres != 0) { + helper::print_and_exit($cmdfh, $outfh, 1, "stat on $name failed\n"); + } +} + +sub process_cmd +{ + my ($dirname, $do_print, $is_alpha) = @_; + +# Get tests directory +my $testdir = $0; +$testdir =~ s/\/\w+.pl$//; + + eval { + if ($is_alpha == 1) { + open2(\*OUTFILE, \*CMDFILE, "yod -sz 1 -quiet -batch $testdir/test_driver --np"); + } else { + open2(\*OUTFILE, \*CMDFILE, "$testdir/test_driver --np"); + } + }; + + if ($@) { + if ($@ =~ /^open2/) { + warn "open2 failed: $!\n$@\n"; + return; + } + die; + + } + + my $outfh = \*OUTFILE; + my $cmdfh = \*CMDFILE; + + if ($is_alpha == 0) { + helper::send_cmd($cmdfh, $outfh, "init", "CALL init incore ".'"0777+0+0"'." 0\n"); + helper::verify_cmd($cmdfh, $outfh, "init incore"); + } + + + # Get a stat buffer + my $cmd = '$buf = ALLOC ( $size = CALL sizeof stat )'."\n"; + helper::send_cmd($cmdfh, $outfh, "alloc", $cmd); + + if ($is_alpha == 0) { + # Make the test directory + $cmd = "CALL mkdir $dirname 0777\n"; + helper::send_cmd($cmdfh, $outfh, "mkdir", $cmd); + helper::verify_cmd($cmdfh, $outfh, "mkdir"); + + + # Change working dir to test dir + $cmd = "CALL chdir $dirname\n"; + helper::send_cmd($cmdfh, $outfh, "chdir", $cmd); + helper::verify_cmd($cmdfh, $outfh, "chdir"); + + + # Create the 3 special files + do_mknod($cmdfh, $outfh, $do_print, "stdin", "0444", 0); + do_mknod($cmdfh, $outfh, $do_print, "stdout", "0222", 1); + do_mknod($cmdfh, $outfh, $do_print, "stderr", "0222", 2); + + # Open the 3 files + do_open($cmdfh, $outfh, "stdin", "O_RDONLY", 0); + do_open($cmdfh, $outfh, "stdout", "O_WRONLY", 1); + do_open($cmdfh, $outfh, "stderr", "O_WRONLY", 2); + } + #helper::send_cmd($cmdfh, $outfh, "debug", "CALL debug 5\n"); + + # Read from stdin, write to stdout and stderr + + # Send "delay" option to read which will give us time to + # put something in stdin (since we can't send an eof) + $cmd = "CALL read 0 ".'$buf 38'." delay\n"; + print $cmdfh $cmd; + # Give time to process command + sleep 1; + + # Send random junk... + print $cmdfh "This message is exactly 38 bytes long\n"; + sleep 0.5; + + # Make sure read was OK + my $res = <$outfh>; + chop($res); + if ($res ne "0000 ") { + helper::print_and_exit($cmdfh, $outfh, 1, "ERROR! Command $cmd failed with code $res\n"); + } + + # See how many bytes we got... + my $bytes = helper::verify_cmd($cmdfh, $outfh, "read"); + $bytes = oct($bytes); + if ($bytes == 0) { + helper::print_and_exit($cmdfh, $outfh, 0, "test_stdfd successful but read nothing\n"); + } + + if ($bytes < 0) { + helper::print_and_exit($cmdfh, $outfh, 0, "test_stdfd unsuccessful\n"); + } + + $cmd = "CALL write 1 ".'$buf '."$bytes\n"; + print $cmdfh $cmd; + + # Suck up the stdout... + $res = <$outfh>; + chop($res); + + $res = <$outfh>; + chop($res); + $res = oct($res); + + if ($res != 0) { + helper::print_and_exit($cmdfh, $outfh, 1, "ERROR! Command $cmd failed with code $res\n"); + } + + helper::verify_cmd($cmdfh, $outfh, "write stdout"); + + $cmd = "CALL write 2 ".'$buf '."$bytes\n"; + helper::send_cmd($cmdfh, $outfh, "write stderr", $cmd); + helper::verify_cmd($cmdfh, $outfh, "write stderr"); + + helper::print_and_exit($cmdfh, $outfh, 0, "test_stdfd successful\n"); +} + + +my $is_alpha = 0; +my $do_print = 0; +my $i; +for ($i=0; $i < @ARGV; $i++) { + if ($ARGV[$i] eq "-alpha") { + $is_alpha =1; + } elsif ($ARGV[$i] eq "-print") { + $do_print = 1; + } +} + +$i--; +my $dirname = $ARGV[$i]; + +process_cmd($dirname, $do_print, $is_alpha); + +exit 0; + diff --git a/libsysio/tests/test_strided.pl b/libsysio/tests/test_strided.pl new file mode 100755 index 0000000..5468d9b --- /dev/null +++ b/libsysio/tests/test_strided.pl @@ -0,0 +1,462 @@ +#!/usr/bin/perl -w + +# +# strided IO test: Perform a series of different reads/writes +# using readx and writex with different buffer +# configurations +# + +use IPC::Open2; + +use strict; +use FindBin; +use lib "$FindBin::Bin"; +use helper; + +sub usage +{ + print "Usage: ./test_rw.pl [-alpha] : Write to/read from file\n"; + exit(-1); +} + +sub verify_result +{ + my ($cmdfh, $outfh, $cmdstr, $exp_val, $eq_op) = @_; + my $print_err = 0; + + my $res = helper::verify_cmd($cmdfh, $outfh, $cmdstr); + $res = oct($res); + + if ($eq_op eq "!=") { + if ($res != $exp_val) { + print STDOUT "Error! $cmdstr returned $res insted of $exp_val\n"; + system("killall test_driver"); + exit(1); + } + } else { + if ($eq_op eq ">") { + if ($res > $exp_val) { + $print_err = 1; + } + } elsif ($eq_op eq "<") { + if ($res < $exp_val) { + $print_err = 1; + } + } elsif ($eq_op eq "==") { + if ($res == $exp_val) { + $print_err = 1; + } + } + if ($print_err == 1) { + print STDOUT "Error! $cmdstr returned $res\n"; + } + } + +} + +# Initilize the iovec number $vecnum +# in the iovec buffer $vecname with buffer +# pos $buf and using len $veclen +sub set_iovec +{ + my ($cmdfh, $outfh, $vecname, $vecnum, $buf, $veclen) = @_; + + my $cmdstr = 'CALL init_iovec $'.$buf." 0 $veclen "; + $cmdstr .= "$vecnum ".'$'."$vecname\n"; + + helper::send_cmd($cmdfh, $outfh, "init_iovec", $cmdstr); + helper::verify_cmd($cmdfh, $outfh, "init_iovec"); +} + + +sub setup_xtvecs +{ + my ($cmdfh, $outfh) = @_; + + # Get size of iovecs + my $cmdstr = '$xtvsize = CALL sizeof xtvec'."\n"; + helper::send_cmd($cmdfh, $outfh, "sizeof", $cmdstr); + my $size = helper::verify_cmd($cmdfh, $outfh, "sizeof xtvec"); + $size = oct($size); + $size = $size * 2; + + # Allocate iovec buffer + $cmdstr = '$xtvbuf'." = ALLOC $size\n"; + helper::send_cmd($cmdfh, $outfh, "alloc", $cmdstr); + + + # Now initilize xtvbuf + $cmdstr = "CALL init_xtvec 0 100 0 ". '$xtvbuf'."\n"; + helper::send_cmd($cmdfh, $outfh, "init_xtvec", $cmdstr); + helper::verify_cmd($cmdfh, $outfh, "init_xtvec"); + + $cmdstr = "CALL init_xtvec 1000 100 1 ". '$xtvbuf'."\n"; + helper::send_cmd($cmdfh, $outfh, "init_xtvec", $cmdstr); + helper::verify_cmd($cmdfh, $outfh, "init_xtvec"); +} + +sub check_buf +{ + + my ($cmdfh, $outfh, $bufsize, $bufname, + $readcmd, $digit, $offset) = @_; + + my $cmdstr = 'CALL checkbuf $'. "$bufname $bufsize $digit $offset\n"; + helper::send_cmd($cmdfh, $outfh, "checkbuf", $cmdstr); + my $res = helper::verify_cmd($cmdfh, $outfh, "checkbuf"); + $res = oct($res); + + if ($res != 0) { + print STDOUT "$readcmd did not return all $digit 's\n"; +} +} + +# Fill given buffer with $digit up to $size +# starting at $offset +sub fill_buf +{ + my ($cmdfh, $outfh, $buf, $digit, $size, $off) = @_; + + my $cmdstr = "CALL setbuf $digit $size ".'$'."$buf $off\n"; + helper::send_cmd($cmdfh, $outfh, "setbuf", $cmdstr); +} + +sub alloc_iovbuf +{ + my ($cmdfh, $outfh, $numbufs, $num) = @_; + + # Get size of iovecs + my $cmdstr = '$iovsize = CALL sizeof iovec'."\n"; + helper::send_cmd($cmdfh, $outfh, "sizeof", $cmdstr); + my $size = helper::verify_cmd($cmdfh, $outfh, "sizeof iovec"); + $size = oct($size); + $size = $size * $numbufs; + + # Allocate iovec buffer + $cmdstr = '$iovbuf'."$num = ALLOC $size\n"; + helper::send_cmd($cmdfh, $outfh, "alloc", $cmdstr); + + my $retstr = "iovbuf".$num; + + return $retstr; +} + +sub do_rwcalls +{ + my ($cmdfh, $outfh, $fh) = @_; + + # Allocate and initilize xtvecs + setup_xtvecs($cmdfh, $outfh); + + # Allocate 2 different iovecs, one for cases + # (a) and (d) and one for cases (b) and (c) + my $iovbuf1 = alloc_iovbuf($cmdfh, $outfh, 3, 0); + my $iovbuf2 = alloc_iovbuf($cmdfh, $outfh, 1, 1); + + # Allocate four buffers, each 200 bytes long + my $cmdstr = '$buf1 '. "= ALLOC 200\n"; + helper::send_cmd($cmdfh, $outfh, "alloc", $cmdstr); + $cmdstr = '$buf2 '. "= ALLOC 200\n"; + helper::send_cmd($cmdfh, $outfh, "alloc", $cmdstr); + $cmdstr = '$buf3 '. "= ALLOC 200\n"; + helper::send_cmd($cmdfh, $outfh, "alloc", $cmdstr); + $cmdstr = '$buf4 '. "= ALLOC 200\n"; + helper::send_cmd($cmdfh, $outfh, "alloc", $cmdstr); + + # Case (a): + # xtvec[] = { { 0, 100 }, {1000, 100} } + # iovec[] = { { buf1, 50}, {buf2, 50}, {buf3, 100} + + # Fill each of the 3 buffers of. They will be filled + # as follows: + # buf1 --> 0- 49: 1 + # --> 49-200: 2 + # buf2 --> 0- 49: 3 + # --> 49-200: 4 + # buf3 --> 0-100: 5 + # --> 100-200: 6 + fill_buf($cmdfh, $outfh, "buf1", 1, 50, 0); + fill_buf($cmdfh, $outfh, "buf1", 2, 150, 50); + fill_buf($cmdfh, $outfh, "buf2", 3, 50, 0); + fill_buf($cmdfh, $outfh, "buf2", 4, 150, 50); + fill_buf($cmdfh, $outfh, "buf3", 5, 100, 0); + fill_buf($cmdfh, $outfh, "buf3", 6, 100, 100); + + # Initiize iovecs + set_iovec($cmdfh, $outfh, $iovbuf1, 0, "buf1", 50); + set_iovec($cmdfh, $outfh, $iovbuf1, 1, "buf2", 50); + set_iovec($cmdfh, $outfh, $iovbuf1, 2, "buf3", 100); + + # Write out to $fh + $cmdstr = 'CALL writex $'."$fh $iovbuf1 3 ".'$xtvbuf '."2\n"; + helper::send_cmd($cmdfh, $outfh, "writex", $cmdstr); + verify_result($cmdfh, $outfh, "writex (case a)", 200, "!="); + + # Clear out the buffers + fill_buf($cmdfh, $outfh, "buf1", 0, 200, 0); + fill_buf($cmdfh, $outfh, "buf2", 0, 200, 0); + fill_buf($cmdfh, $outfh, "buf3", 0, 200, 0); + + # Read it back + $cmdstr = 'CALL readx $'."$fh $iovbuf1 3 ".'$xtvbuf '."2\n"; + helper::send_cmd($cmdfh, $outfh, "readx", $cmdstr); + verify_result($cmdfh, $outfh, "readx (case a)", 200, "!="); + + # Make sure we got what we expected... + check_buf($cmdfh, $outfh, 50, "buf1", "readx (case a)", 1, 0); + check_buf($cmdfh, $outfh, 50, "buf2", "readx (case a)", 3, 0); + check_buf($cmdfh, $outfh, 100, "buf3", "readx (case a)", 5, 0); + + # Case (b): + # xtvec[] = { { 0, 100 }, {1000, 100} } + # iovec[] = { { buf4, 200} } + + + # Fill buf4 with 7's... + fill_buf($cmdfh, $outfh, "buf4", 7, 200, 0); + + # Initiize iovecs + set_iovec($cmdfh, $outfh, $iovbuf2, 0, "buf4", 200); + + # Write out to $fh + $cmdstr = 'CALL writex $'."$fh ".'$'."$iovbuf2 1 ".'$xtvbuf '."2\n"; + helper::send_cmd($cmdfh, $outfh, "writex", $cmdstr); + verify_result($cmdfh, $outfh, "writex (case b)", 200, "!="); + + # Clear out the buffer + fill_buf($cmdfh, $outfh, "buf4", 0, 200, 0); + + # Read it back + $cmdstr = 'CALL readx $'."$fh $iovbuf2 1 ".'$xtvbuf '."2\n"; + helper::send_cmd($cmdfh, $outfh, "readx", $cmdstr); + verify_result($cmdfh, $outfh, "readx (case b)", 200, "!="); + + # Make sure we got what we expected... + check_buf($cmdfh, $outfh, 200, "buf4", "readx (case b)", 7, 0); + + + # Case (c): + # xtvec[] = { { 0, 100 }, {1000, 100} } + # iovec[] = { { buf4, 40} } + + # Fill buf4 with 8's... + fill_buf($cmdfh, $outfh, "buf4", 8, 200, 0); + + # Initiize iovecs + set_iovec($cmdfh, $outfh, $iovbuf2, 0, "buf4", 40); + + # Write out to $fh + $cmdstr = 'CALL writex $'."$fh $iovbuf2 1 ".'$xtvbuf '."2\n"; + helper::send_cmd($cmdfh, $outfh, "writex", $cmdstr); + verify_result($cmdfh, $outfh, "writex (case c)", 40, "!="); + + # Clear out the buffer + fill_buf($cmdfh, $outfh, "buf4", 0, 200, 0); + + # Read it back + $cmdstr = 'CALL readx $'."$fh $iovbuf2 1 ".'$xtvbuf '."2\n"; + helper::send_cmd($cmdfh, $outfh, "readx", $cmdstr); + verify_result($cmdfh, $outfh, "readx (case c)", 40, "!="); + + # Make sure we got what we expected... + check_buf($cmdfh, $outfh, 40, "buf4", "readx (case c)", 8, 0); + + + # Case (d): + # xtvec[] = { { 0, 100 }, {1000, 100} } + # iovec[] = { { buf1, 40}, {buf2, 150}, {buf3, 200} } + + # Fill each of the 3 buffers of. They will be filled + # as follows: + # buf1 --> 0- 39: 1 + # --> 39-200: 2 + # buf2 --> 0-150: 3 + # --> 150-200: 4 + # buf3 --> 0- 9: 5 + # --> 10-200: 6 + fill_buf($cmdfh, $outfh, "buf1", 1, 40, 0); + fill_buf($cmdfh, $outfh, "buf1", 2, 160, 40); + fill_buf($cmdfh, $outfh, "buf2", 3, 150, 0); + fill_buf($cmdfh, $outfh, "buf2", 4, 50, 150); + fill_buf($cmdfh, $outfh, "buf3", 5, 10, 0); + fill_buf($cmdfh, $outfh, "buf3", 6, 190, 10); + + # Initiize iovecs + set_iovec($cmdfh, $outfh, $iovbuf1, 0, "buf1", 40); + set_iovec($cmdfh, $outfh, $iovbuf1, 1, "buf2", 150); + set_iovec($cmdfh, $outfh, $iovbuf1, 2, "buf3", 200); + + # Write out to $fh + $cmdstr = 'CALL writex $'."$fh $iovbuf1 3 ".'$xtvbuf '."2\n"; + helper::send_cmd($cmdfh, $outfh, "writex", $cmdstr); + verify_result($cmdfh, $outfh, "writex (case d)", 200, "!="); + + # Clear out the buffers + fill_buf($cmdfh, $outfh, "buf1", 0, 200, 0); + fill_buf($cmdfh, $outfh, "buf2", 0, 200, 0); + fill_buf($cmdfh, $outfh, "buf3", 0, 200, 0); + + # Read it back + $cmdstr = 'CALL readx $'."$fh $iovbuf1 3 ".'$xtvbuf '."2\n"; + helper::send_cmd($cmdfh, $outfh, "readx", $cmdstr); + verify_result($cmdfh, $outfh, "readx (case d)", 200, "!="); + + # Make sure we got what we expected... + check_buf($cmdfh, $outfh, 40, "buf1", "readx (case d)", 1, 0); + check_buf($cmdfh, $outfh, 150, "buf2", "readx (case d)", 3, 0); + check_buf($cmdfh, $outfh, 10, "buf3", "readx (case d)", 5, 0); + + # Case (e): + # xtvec[] = { { 0, 100 }, {1000, 100} } + # iovec[] = { { buf1, 30}, {buf2, 30}, {buf3, 30} } + + # Fill each of the 3 buffers as follows: + # buf1 --> 0- 30: 1 + # --> 30-200: 2 + # buf2 --> 0- 30: 3 + # --> 30-200: 4 + # buf3 --> 0- 30: 5 + # --> 30-200: 6 + fill_buf($cmdfh, $outfh, "buf1", 1, 30, 0); + fill_buf($cmdfh, $outfh, "buf1", 2, 170, 30); + fill_buf($cmdfh, $outfh, "buf2", 3, 30, 0); + fill_buf($cmdfh, $outfh, "buf2", 4, 170, 30); + fill_buf($cmdfh, $outfh, "buf3", 5, 30, 0); + fill_buf($cmdfh, $outfh, "buf3", 6, 170, 30); + + # Initiize iovecs + set_iovec($cmdfh, $outfh, $iovbuf1, 0, "buf1", 30); + set_iovec($cmdfh, $outfh, $iovbuf1, 1, "buf2", 30); + set_iovec($cmdfh, $outfh, $iovbuf1, 2, "buf3", 30); + + # Write out to $fh + $cmdstr = 'CALL writex $'."$fh $iovbuf1 3 ".'$xtvbuf '."2\n"; + helper::send_cmd($cmdfh, $outfh, "writex", $cmdstr); + verify_result($cmdfh, $outfh, "writex (case e)", 90, "!="); + + # Clear out the buffers + fill_buf($cmdfh, $outfh, "buf1", 0, 200, 0); + fill_buf($cmdfh, $outfh, "buf2", 0, 200, 0); + fill_buf($cmdfh, $outfh, "buf3", 0, 200, 0); + + # Read it back + $cmdstr = 'CALL readx $'."$fh $iovbuf1 3 ".'$xtvbuf '."2\n"; + helper::send_cmd($cmdfh, $outfh, "readx", $cmdstr); + verify_result($cmdfh, $outfh, "readx (case e)", 90, "!="); + + # Make sure we got what we expected... + check_buf($cmdfh, $outfh, 30, "buf1", "readx (case e)", 1, 0); + check_buf($cmdfh, $outfh, 30, "buf2", "readx (case e)", 3, 0); + check_buf($cmdfh, $outfh, 30, "buf3", "readx (case e)", 5, 0); + + # Case (f): + # xtvec[] = { { 0, 100 }, {1000, 100} } + # iovec[] = { { buf1, 30}, {buf2, 90}, {buf3, 200} } + + # Fill each of the 3 buffers as follows: + # buf1 --> 0- 30: 1 + # --> 30-200: 2 + # buf2 --> 0- 70: 3 + # --> 70- 90: 4 + # --> 90-200: 5 + # buf3 --> 0-200: 6 + fill_buf($cmdfh, $outfh, "buf1", 1, 30, 0); + fill_buf($cmdfh, $outfh, "buf1", 2, 170, 30); + fill_buf($cmdfh, $outfh, "buf2", 3, 70, 0); + fill_buf($cmdfh, $outfh, "buf2", 4, 90, 70); + fill_buf($cmdfh, $outfh, "buf2", 5, 110, 90); + fill_buf($cmdfh, $outfh, "buf3", 6, 200, 0); + + # Initiize iovecs + set_iovec($cmdfh, $outfh, $iovbuf1, 0, "buf1", 30); + set_iovec($cmdfh, $outfh, $iovbuf1, 1, "buf2", 90); + set_iovec($cmdfh, $outfh, $iovbuf1, 2, "buf3", 200); + + # Write out to $fh + $cmdstr = 'CALL writex $'."$fh $iovbuf1 3 ".'$xtvbuf '."2\n"; + helper::send_cmd($cmdfh, $outfh, "writex", $cmdstr); + verify_result($cmdfh, $outfh, "writex (case f)", 200, "!="); + + # Clear out the buffers + fill_buf($cmdfh, $outfh, "buf1", 0, 200, 0); + fill_buf($cmdfh, $outfh, "buf2", 0, 200, 0); + fill_buf($cmdfh, $outfh, "buf3", 0, 200, 0); + + # Read it back + $cmdstr = 'CALL readx $'."$fh $iovbuf1 3 ".'$xtvbuf '."2\n"; + helper::send_cmd($cmdfh, $outfh, "readx", $cmdstr); + verify_result($cmdfh, $outfh, "readx (case f)", 200, "!="); + + # Make sure we got what we expected... + check_buf($cmdfh, $outfh, 30, "buf1", "readx (case f)", 1, 0); + check_buf($cmdfh, $outfh, 70, "buf2", "readx (case f)", 3, 0); + check_buf($cmdfh, $outfh, 20, "buf2", "readx (case f)", 4, 70); + check_buf($cmdfh, $outfh, 70, "buf3", "readx (case f)", 6, 0); + +} + + +sub process_cmd +{ + my ($file, $is_alpha) = @_; + + # Get tests directory + my $testdir = $FindBin::Bin; + + eval { + if ($is_alpha == 0) { + open2(\*OUTFILE, \*CMDFILE, "$testdir/test_driver --np"); + } else { + open2(\*OUTFILE, \*CMDFILE, + "yod -quiet -sz 1 $testdir/test_driver --np"); + } + }; + + if ($@) { + if ($@ =~ /^open2/) { + warn "open2 failed: $!\n$@\n"; + return; + } + die; + + } + + my $outfh = \*OUTFILE; + my $cmdfh = \*CMDFILE; + + if ($is_alpha == 0) { + helper::send_cmd($cmdfh, $outfh, "init", "CALL init\n"); + } + + # Open file + my $cmdstr = '$fd = CALL open '."$file O_RDWR|O_CREAT|O_TRUNC S_IRWXU\n"; + helper::send_cmd($cmdfh, $outfh, "open", $cmdstr); + helper::verify_cmd($cmdfh, $outfh, $cmdstr); + + + do_rwcalls($cmdfh, $outfh, "fd"); + + # Clean up + $cmdstr = 'CALL close $fd'."\n"; + helper::send_cmd($cmdfh, $outfh, "close", $cmdstr); + +# system("rm -f $file"); + helper::print_and_exit($cmdfh, $outfh, 0, "strided IO test successful\n"); +} + +my $currarg = 0; +my $is_alpha = 0; + +if (@ARGV < 1) { + usage; +} elsif (@ARGV > 1 ) { + if ($ARGV[$currarg++] eq "-alpha") { + $is_alpha = 1; + } +} + +my $file = $ARGV[$currarg]; + +process_cmd($file, $is_alpha); + +exit 0; diff --git a/libsysio/tests/test_symlink.pl b/libsysio/tests/test_symlink.pl new file mode 100755 index 0000000..23d5185 --- /dev/null +++ b/libsysio/tests/test_symlink.pl @@ -0,0 +1,247 @@ +#!/usr/bin/perl -w + +# +# symlink test: Verify that symbolic links work +# + +use IPC::Open2; + +use strict; +use FindBin; +use lib "$FindBin::Bin"; +use helper; + +sub usage +{ + print "Usage: ./test_symlink.pl [-alpha] : Create a symlink from src to dest\n"; + exit(-1); +} + +sub clean_exit +{ + my ($cmdfh, $outfh, $exit_num, $exit_str) = @_; + + print STDOUT "$exit_str"; + + # Free buffers + my $cmdstr = 'FREE $srcbuf'."\n"; + + print $cmdfh $cmdstr; + + my $res = <$outfh>; + chop($res); + if ($res ne "0000 ") { + print STDOUT "ERROR! Failed to free srcbuf (code $res)\n"; + } + + $cmdstr = 'FREE $destbuf'."\n"; + + print $cmdfh $cmdstr; + + $res = <$outfh>; + chop($res); + if ($res ne "0000 ") { + print STDOUT "ERROR! Failed to free destbuf (code $res)\n"; + } + + print $cmdfh "exit\n"; + close $outfh; + + # Give test_driver time to finish + sleep 0.000001; + + exit $exit_num; +} + +sub process_cmd +{ + my ($src, $dest, $is_alpha) = @_; + + # Get tests directory + my $testdir = $FindBin::Bin; + + eval { + if ($is_alpha == 0) { + open2(\*OUTFILE, \*CMDFILE, "$testdir/test_driver --np"); + } else { + open2(\*OUTFILE, \*CMDFILE, "yod -quiet -sz 1 $testdir/test_driver --np"); + } + }; + + if ($@) { + if ($@ =~ /^open2/) { + warn "open2 failed: $!\n$@\n"; + return; + } + die; + + } + + my $outfh = \*OUTFILE; + my $cmdfh = \*CMDFILE; + + if ($is_alpha == 0) { + helper::send_cmd($cmdfh, $outfh, "init", "CALL init\n"); + } + + # Get the filesize of src + my $size = -s $src; + my $bufsize; + + if ( $size > 1024) { # Arbitrary limit + $bufsize = 1024; + } else { + $bufsize = $size; + } + + # Create the symbolic link from src to dest + my $cmdstr = "CALL symlink $src $dest\n"; + helper::send_cmd($cmdfh, $outfh, "open", $cmdstr); + + helper::verify_cmd($cmdfh, $outfh, "symlink"); + + # Open src + $cmdstr = '$src = CALL open '."$src O_RDONLY\n"; + helper::send_cmd($cmdfh, $outfh, "open", $cmdstr); + + # Open dest + $cmdstr = '$dest = CALL open '."$dest O_RDONLY\n"; + helper::send_cmd($cmdfh, $outfh, "open", $cmdstr); + + my $res = helper::verify_cmd($cmdfh, $outfh, "open $dest"); + + # Allocate buffer for src + $cmdstr = '$srcbuf = ALLOC '."$bufsize\n"; + helper::send_cmd($cmdfh, $outfh, "ALLOC", $cmdstr); + + # Allocate buffer for dest + $cmdstr = '$destbuf = ALLOC '."$bufsize\n"; + helper::send_cmd($cmdfh, $outfh, "ALLOC", $cmdstr); + + + # Read size bytes from src and dest, then compare them and verify they + # are the same + $cmdstr = 'CALL read $src $srcbuf '."$bufsize\n"; + helper::send_cmd($cmdfh, $outfh, "read $src", $cmdstr); + + $res = helper::verify_cmd($cmdfh, $outfh, "read $src"); + my $readb = oct($res); + + # Now read $readb from dest + $cmdstr = 'CALL read $dest $destbuf '."$readb\n"; + helper::send_cmd($cmdfh, $outfh, "read $dest", $cmdstr); + + $res = helper::verify_cmd($cmdfh, $outfh, "read $dest"); + + my $errstr; + if ($readb != oct($res)) { + $errstr = "ERROR! Read $readb bytes from src but only $res bytes from dest\n"; + clean_exit($cmdfh, $outfh, 1, $errstr); + } + + # Compare the two buffers + $cmdstr = 'CALL cmpstr $srcbuf $destbuf'."\n"; + helper::send_cmd($cmdfh, $outfh, "cmpstr", $cmdstr); + + # Verify that it returned an error + $cmdstr = 'PRINT $$'; + $cmdstr .= "\n"; + helper::send_cmd($cmdfh, $outfh, "PRINT", $cmdstr); + + $res = <$outfh>; + chop($res); + + $res = helper::verify_cmd($cmdfh, $outfh, "cmpstr"); + $res = oct($res); + if ($res != 0) { + $errstr = "ERROR! Buffers from $src and $dest do not match\n"; + clean_exit($cmdfh, $outfh, 1, $errstr); + } + + # Clean up + $cmdstr = 'CALL close $src'."\n"; + helper::send_cmd($cmdfh, $outfh, "close", $cmdstr); + $cmdstr = 'CALL close $dest'."\n"; + helper::send_cmd($cmdfh, $outfh, "close", $cmdstr); + + # Clear out destbuf + $cmdstr = 'CALL clear $destbuf'."\n"; + helper::send_cmd($cmdfh, $outfh, "CLEAR", $cmdstr); + + # Now remove the symbolic link and make sure everything stays the same + + # Remove the link (this assumes the link is not in incore) + $cmdstr = "CALL unlink $dest\n"; + helper::send_cmd($cmdfh, $outfh, "unlink", $cmdstr); + helper::verify_cmd($cmdfh, $outfh, "unlink"); + + # Attempt to open the symbolic link. This should return an error + $cmdstr = 'CALL open '."$dest O_RDONLY\n"; + helper::send_cmd($cmdfh, $outfh, "open", $cmdstr); + + # Verify that it returned an error + $cmdstr = 'PRINT $$'; + $cmdstr .= "\n"; + helper::send_cmd($cmdfh, $outfh, "PRINT", $cmdstr); + + $res = <$outfh>; + chop($res); + + if ($res ne "0xffffffff") { + $errstr = "ERROR! Open on $dest succeeded (should have failed)\n"; + clean_exit($cmdfh, $outfh, 1, $errstr); + } + + # Now read from the src again and make sure it matches the original + + # Open src + $cmdstr = '$src2 = CALL open '."$src O_RDONLY\n"; + helper::send_cmd($cmdfh, $outfh, "open", $cmdstr); + helper::verify_cmd($cmdfh, $outfh, "open $src(2)"); + + $cmdstr = 'CALL read $src2 $destbuf '."$readb\n"; + helper::send_cmd($cmdfh, $outfh, "read $src(2)", $cmdstr); + + $res = helper::verify_cmd($cmdfh, $outfh, "read $src(2)"); + + if ($readb != oct($res)) { + $errstr = "ERROR! Read $readb bytes from src originally but now only $res bytes\n"; + clean_exit($cmdfh, $outfh, 1, $errstr); + } + + # Compare the two buffers + $cmdstr = 'CALL cmpstr $srcbuf $destbuf'."\n"; + helper::send_cmd($cmdfh, $outfh, "cmpstr", $cmdstr); + $res = helper::verify_cmd($cmdfh, $outfh, "cmpstr"); + $res = oct($res); + if ($res != 0) { + $errstr = "ERROR! Original buffers from $src and new buf do not match\n"; + clean_exit($cmdfh, $outfh, 1, $errstr); + } + + # Clean up + $cmdstr = 'CALL close $src2'."\n"; + helper::send_cmd($cmdfh, $outfh, "close", $cmdstr); + + clean_exit($cmdfh, $outfh, 0, "Symlink test successful\n"); + exit 0; +} + +my $currarg = 0; +my $is_alpha = 0; + +if (@ARGV < 2) { + usage; +} elsif (@ARGV > 2 ) { + if ($ARGV[$currarg++] eq "-alpha") { + $is_alpha = 1; + } +} + +my $src = $ARGV[$currarg++]; +my $dest = $ARGV[$currarg]; + +process_cmd($src, $dest, $is_alpha); + + +exit 0; diff --git a/libsysio/tests/test_unlink.c b/libsysio/tests/test_unlink.c new file mode 100644 index 0000000..9d019d5 --- /dev/null +++ b/libsysio/tests/test_unlink.c @@ -0,0 +1,167 @@ +/* + * This Cplant(TM) source code is the property of Sandia National + * Laboratories. + * + * This Cplant(TM) source code is copyrighted by Sandia National + * Laboratories. + * + * The redistribution of this Cplant(TM) source code is subject to the + * terms of the GNU Lesser General Public License + * (see cit/LGPL or http://www.gnu.org/licenses/lgpl.html) + * + * Cplant(TM) Copyright 1998-2003 Sandia Corporation. + * Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive + * license for use of this work by or on behalf of the US Government. + * Export of this program may require a license from the United States + * Government. + */ + +/* + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Questions or comments about this library should be sent to: + * + * Lee Ward + * Sandia National Laboratories, New Mexico + * P.O. Box 5800 + * Albuquerque, NM 87185-1110 + * + * lee@sandia.gov + */ + +#include +#include +#include +#ifndef REDSTORM +#include +#else +#include +#endif +#include +#include +#include +#if 0 +#include +#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" + " [ ...\n]"); + + exit(1); +} diff --git a/libsysio/tests/verifier.pl b/libsysio/tests/verifier.pl new file mode 100755 index 0000000..3afc51b --- /dev/null +++ b/libsysio/tests/verifier.pl @@ -0,0 +1,161 @@ +#!/usr/bin/perl -w + +# Verifies that the contents of a given file produced by producer.pl with the given +# seed are good + +use IPC::Open2; + +use strict; +use helper; + +sub usage +{ + print "Usage: ./verifier.pl <-seed seed> <-file fname> : Verifies that file fname,\n"; + print " : produced with the given \n"; + print " : seed matches\n"; + exit(-1); +} + +sub get_buf +{ + my $MAX_SIZE = 2147483648; + + my $str; + my $num; + my $len = 0; + + while ($len < 512) { + $num = rand $MAX_SIZE; + my $tmpstr = sprintf("%d", $num); + $str .= $tmpstr; + $len += length $tmpstr; + } + + return ($len, $str); +} + + +sub check_file +{ + my ($cmdfh, $outfh, $filename) = @_; + + + # Allocate the read buffer + my $cmd = '$buf = ALLOC 1024'."\n"; + helper::send_cmd($cmdfh, $outfh, "alloc", $cmd); + + # Open the file + $cmd = '$fd = CALL open '."$filename O_RDONLY\n"; + helper::send_cmd($cmdfh, $outfh, "open", $cmd); + + # Verify the system call's output + helper::verify_cmd($cmdfh, $outfh, "open"); + + my $total = 0; + my $bytes = 0; + + # Read all of the file in 1024 byte chunks + do { + + # Clear the buffer + $cmd = 'CALL clear $buf'."\n"; + helper::send_cmd($cmdfh, $outfh, "clear", $cmd); + + my ($len, $buf) = get_buf; + + $cmd = 'CALL read $fd $buf '."$len\n"; + helper::send_cmd($cmdfh, $outfh, "read", $cmd); + $bytes = helper::verify_cmd($cmdfh, $outfh, "read"); + $bytes = oct($bytes); + $total += $bytes; + if ($bytes > 0) { + + # Print out the buffer + $cmd = 'PRINT $buf 0 1 STR'."\n"; + helper::send_cmd($cmdfh, $outfh, "print", $cmd); + my $str = <$outfh>; + chop($str); + if ($bytes > $len) { + $str = substr($str, 0, $len-1); + } elsif ($len > $bytes) { + $buf = substr($buf, 0, $bytes); + } + if ($str ne $buf) { + my $errstr = "ERROR! Str $str is not equal to str $buf\n"; + helper::print_and_exit($cmdfh, $outfh, 1, $errstr); + } + } + } while ($bytes > 0); + +} + +sub verify_file +{ + my ($filename, $is_alpha) = @_; + + eval { + if ($is_alpha == 0) { + open2(\*OUTFILE, \*CMDFILE, "./test_driver --np"); + } else { + open2(\*OUTFILE, \*CMDFILE, + "yod -batch -quiet -sz 1 ./test_driver --np"); + } + }; + + if ($@) { + if ($@ =~ /^open2/) { + warn "open2 failed: $!\n$@\n"; + return; + } + die; + + } + + my $outfh = \*OUTFILE; + my $cmdfh = \*CMDFILE; + + if ($is_alpha == 0) { + helper::send_cmd($cmdfh, $outfh, "init", "CALL init\n"); + } + + # Now check the file + check_file($cmdfh, $outfh, $filename); + + # Close the file + my $cmd = 'CALL close $fd'."\n"; + helper::send_cmd($cmdfh, $outfh, "close", $cmd); + + helper::verify_cmd($cmdfh, $outfh, "close"); + + # All done + helper::print_and_exit($cmdfh, $outfh, 0, "File $filename valid\n"); +} + + +my $is_alpha = 0; +my $seed = time; +my $filename = "randfile.$seed.$$"; +my $bytes = 1024; +for (my $i = 0; $i < @ARGV; $i++) +{ + if ($ARGV[$i] eq "-file") { + $i++; + $filename = $ARGV[$i]; + } elsif ($ARGV[$i] eq "-seed") { + $i++; + $seed = $ARGV[$i]; + } elsif ($ARGV[$i] eq "-alpha") { + $is_alpha = 1; + } +} + +# seed the randome number generator +srand $seed; + +verify_file($filename, $is_alpha); + +exit 0; + + + +