summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael I. Bushnell <mib@gnu.org>1996-07-18 04:35:29 +0000
committerMichael I. Bushnell <mib@gnu.org>1996-07-18 04:35:29 +0000
commit94cef36797600d11a50d09828fa80df8a73dfd1c (patch)
treeb7cba9afef95489eedef534d3e6946eb13f595ba
parent88dbbbf9e48e24f1ac007c1e4eeffd9caf8e2fad (diff)
*** empty log message ***
-rw-r--r--BUGS33
-rw-r--r--COPYING339
-rw-r--r--INSTALL198
-rw-r--r--INSTALL-cross119
-rw-r--r--NEWS575
-rw-r--r--README23
-rw-r--r--SOURCES.0.0196
-rw-r--r--TODO227
-rw-r--r--boot/frank1.ld94
-rw-r--r--boot/frankemul.ld107
-rw-r--r--exec/core.c264
-rw-r--r--exec/elfcore.c100
-rw-r--r--exec/exectrans.c81
-rw-r--r--exec/gcore.c88
-rw-r--r--hurd/=pending-changes26
-rw-r--r--libfshelp/trans.h32
-rw-r--r--libnetfs/execserver.h23
-rw-r--r--libnetfs/file-exec.c164
-rw-r--r--libports/default-uninhibitable-rpcs.c27
-rw-r--r--libports/import-port.c116
-rw-r--r--libps/ps_msg.h633
-rw-r--r--libps/ps_term.h216
-rw-r--r--libtreefs/Makefile40
-rw-r--r--libtreefs/defhooks.c80
-rw-r--r--libtreefs/dir-hooks.c136
-rw-r--r--libtreefs/dir-lookup.c305
-rw-r--r--libtreefs/fs-mutate.h30
-rw-r--r--libtreefs/fsys-getroot.c144
-rw-r--r--libtreefs/fsys-hooks.c91
-rw-r--r--libtreefs/fsys-startup.c36
-rw-r--r--libtreefs/fsys.c127
-rw-r--r--libtreefs/hooks.c59
-rw-r--r--libtreefs/mdir.c92
-rw-r--r--libtreefs/mig-decls.h41
-rw-r--r--libtreefs/nlist.c70
-rw-r--r--libtreefs/node-hooks.c176
-rw-r--r--libtreefs/rights.c96
-rw-r--r--libtreefs/s-dir.c112
-rw-r--r--libtreefs/s-file.c233
-rw-r--r--libtreefs/s-fsys.c77
-rw-r--r--libtreefs/s-io.c284
-rw-r--r--libtreefs/trans-help.c129
-rw-r--r--libtreefs/trans-start.c65
-rw-r--r--libtreefs/treefs-hooks.h401
-rw-r--r--libtreefs/treefs-s-hooks.h231
-rw-r--r--libtreefs/treefs.h472
-rwxr-xr-xmkinstalldirs40
-rw-r--r--mount/mount.defs109
-rw-r--r--mount/mount.h72
-rw-r--r--mount/mount_types.h61
-rw-r--r--nfs/pager.c448
-rw-r--r--nfs/rpcsvc/mount.h81
-rw-r--r--nfs/rpcsvc/nfs_prot.h343
-rw-r--r--nfsd/Makefile34
-rw-r--r--nfsd/cache.c496
-rw-r--r--nfsd/fsys.c192
-rw-r--r--nfsd/loop.c233
-rw-r--r--nfsd/main.c78
-rw-r--r--nfsd/nfsd.h128
-rw-r--r--nfsd/ops.c652
-rw-r--r--nfsd/proctables.c57
-rw-r--r--nfsd/xdr.c204
-rw-r--r--release/=announce-0.067
-rw-r--r--release/COPYING.LIB481
-rw-r--r--release/checklist14
-rwxr-xr-xrelease/fstab-to-settrans1
-rw-r--r--tasks169
-rw-r--r--utils/psout.h32
-rw-r--r--utils/x.c248
69 files changed, 11448 insertions, 0 deletions
diff --git a/BUGS b/BUGS
new file mode 100644
index 00000000..1c58c181
--- /dev/null
+++ b/BUGS
@@ -0,0 +1,33 @@
+This file is for bugs in Mach. Bugs in the Hurd go into TODO.
+
+Do not ever delete a bug from this list; new Mach releases need to be
+checked to make sure fixed bugs stay fixed, and so this list must
+never get truncated. -mib
+
+--Reported, verified fixed--
+
+--Reported, claimed fixed--
+MiG user stubs need to destroy reply port on any message transmission
+error, not just a limited set.
+
+--Reported--
+Bug in vm_fault: when vm_fault on a shadow page:
+First page from anonymous copy; returns unavaliable. Then fault on
+the actual page and block. This block is interruptible, but a lock is
+being held on the copy object (because it's FIRST_M). If the sleep is
+interrupted, the lock gets released, but unfortunately, it could also
+be suspended, and that's a lose.
+
+pager flush of wired pages can block forever uninterruptibly.
+
+unwiring of pages should call PAGE_WAKEUP
+
+permission arg of vm_wire is not passed to vm_fault, so that vm_fault
+overeagerly wires the current protection, which might be more than the
+permission arg of vm_wire.
+
+When wiring, vm_fault uses current permission instead of max
+permission; this will cause a failure of vm_wire if the current
+permission is later promoted.
+
+Patch for MiG dealing when sreplyport and mach_port_poly_t are used together.
diff --git a/COPYING b/COPYING
new file mode 100644
index 00000000..a43ea212
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,339 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 675 Mass Ave, Cambridge, MA 02139, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, 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 or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+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 give any other recipients of the Program a copy of this License
+along with the Program.
+
+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 Program or any portion
+of it, thus forming a work based on the Program, 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) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+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 Program, 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 Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) 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; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, 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 executable. However, as a
+special exception, the source code 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.
+
+If distribution of executable or 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 counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program 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.
+
+ 5. 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 Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program 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 to
+this License.
+
+ 7. 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 Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program 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 Program.
+
+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.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program 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.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the 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 Program
+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 Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, 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
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "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 PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. 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 PROGRAM 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 PROGRAM (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 PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ Appendix: How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) 19yy <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) 19yy name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/INSTALL b/INSTALL
new file mode 100644
index 00000000..8b1edb29
--- /dev/null
+++ b/INSTALL
@@ -0,0 +1,198 @@
+-*- Text -*-
+GNU Hurd 0.0
+
+This is the Hurd. Welcome.
+
+This file contains instructions for compiling and installing the Hurd
+from your existing Hurd system.
+
+If you are running any other kind of system whatsoever, these
+instructions will *NOT* be sufficient. The file INSTALL-cross
+contains some past instructions for doing so, but it's too much
+trouble to maintain them and make them easier. Your best bet is to
+start with a running Hurd system already.
+
+The Hurd and the GNU C Library each need each other in order to
+compile. If you are installing both, please follow the directions
+"Building the Hurd and libc together". If the C library version you
+want to use is already installed, and you know both it and this
+version of the Hurd will interoperate together, then see the
+instructions "Bulding the Hurd by itself" below.
+
+The Hurd version 0.0 is known to work with version XXX of the library.
+
+
+Configuring the Hurd
+====================
+
+The `configure' shell script attempts to guess correct values for
+various system-dependent variables used during compilation. It uses
+those values to create a `Makefile' in each directory of the package.
+It may also create one or more `.h' files containing system-dependent
+definitions. Finally, it creates a shell script `config.status' that
+you can run in the future to recreate the current configuration, a
+file `config.cache' that saves the results of its tests to speed up
+reconfiguring, and a file `config.log' containing compiler output
+(useful mainly for debugging `configure').
+
+If you need to do unusual things to compile the package, please try to
+figure out how `configure' could check whether to do them, and mail
+diffs or instructions to the address given in the `README' so they can
+be considered for the next release. If at some point `config.cache'
+contains results you don't want to keep, you may remove or edit it.
+
+The file `configure.in' is used to create `configure' by a program
+called `autoconf'. You only need `configure.in' if you want to change
+it or regenerate `configure' using a newer version of `autoconf'.
+
+
+Building the Hurd, Mach4, and libc together
+===========================================
+
+1. Configure mach4.
+
+2. `make' mach4.
+
+3. Do `make install' in <mach4-build>/mig. ONLY.
+
+4. Do `make install' in <mach4-build>/include. ONLY.
+
+5. Configure the Hurd with `configure'.
+
+6. In the Hurd directory, type `make install-hdrs'.
+
+7. Configure libc.
+
+8. `make install' libc.
+
+9. `make' and `make install' Hurd.
+
+10. `make install' mach4.
+
+
+Building the Hurd and libc together
+===================================
+
+1. `cd' to the directory containing the Hurd's source code and type
+ `./configure' to configure the Hurd.
+
+2. Type `make install-hdrs' to install the Hurd's header files.
+
+3. Follow the instructions in the GNU C Library for configuring and
+ installing GNU libc.
+
+4. Return to the directory containing the Hurd's source code and type
+ `make' to compile the Hurd.
+
+5. Type `make install' to install the Hurd.
+
+
+Building the Hurd by itself
+===========================
+
+The simplest way to compile this package is:
+
+ 1. `cd' to the directory containing the package's source code and type
+ `./configure' to configure the package for your system. If you're
+ using `csh' on an old version of System V, you might need to type
+ `sh ./configure' instead to prevent `csh' from trying to execute
+ `configure' itself.
+
+ Running `configure' takes awhile. While running, it prints some
+ messages telling which features it is checking for.
+
+ 2. Type `make' to compile the package.
+
+ 3. Optionally, type `make check' to run any self-tests that come with
+ the package.
+
+ 4. Type `make install' to install the programs and any data files and
+ documentation.
+
+ 5. You can remove the program binaries and object files from the
+ source code directory by typing `make clean'. To also remove the
+ files that `configure' created (so you can compile the package for
+ a different kind of computer), type `make distclean'. There is
+ also a `make maintainer-clean' target, but that is intended mainly
+ for the package's developers. If you use it, you may have to get
+ all sorts of other programs in order to regenerate files that came
+ with the distribution.
+
+Compiling For Multiple Architectures
+====================================
+
+You can compile the package for more than one kind of computer at the
+same time, by placing the object files for each architecture in their
+own directory. `cd' to the directory where you want the object files
+and executables to go and run the `configure' script. `configure'
+automatically checks for the source code in the directory that
+`configure' is in and in `..'.
+
+Installation Names
+==================
+
+By default, `make install' will install the package's files in `/bin',
+`/man', etc. You can specify an installation prefix by giving
+`configure' the option `--prefix=PATH'.
+
+You can specify separate installation prefixes for
+architecture-specific files and architecture-independent files. If
+you give `configure' the option `--exec-prefix=PATH', the package will
+use PATH as the prefix for installing programs and libraries.
+Documentation and other data files will still use the regular prefix.
+
+In addition, if you use an unusual directory layout you can give
+options like `--bindir=PATH' to specify different values for
+particular kinds of files. Run `configure --help' for a list of the
+directories you can set and what kinds of files go in them.
+
+If the package supports it, you can cause programs to be installed
+with an extra prefix or suffix on their names by giving `configure'
+the option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
+
+Please note, however, that the Hurd knows where it is located in the
+filesystem. If you have installed it in an unusual location, the
+system might not work properly, or at all. The chief utility of these
+options for the Hurd is to allow you to "install" in some alternate
+location, and then copy these to the actual root filesystem later.
+
+Sharing Defaults
+================
+
+If you want to set default values for `configure' scripts to share,
+you can create a site shell script called `config.site' that gives
+default values for variables like `CC', `cache_file', and `prefix'.
+`configure' looks for `PREFIX/share/config.site' if it exists, then
+`PREFIX/etc/config.site' if it exists. Or, you can set the
+`CONFIG_SITE' environment variable to the location of the site script.
+A warning: not all `configure' scripts look for a site script.
+
+Operation Controls
+==================
+
+ `configure' recognizes the following options to control how it
+operates.
+
+`--cache-file=FILE'
+ Use and save the results of the tests in FILE instead of
+ `./config.cache'. Set FILE to `/dev/null' to disable caching, for
+ debugging `configure'.
+
+`--help'
+ Print a summary of the options to `configure', and exit.
+
+`--quiet'
+`--silent'
+`-q'
+ Do not print messages saying which checks are being made.
+
+`--srcdir=DIR'
+ Look for the package's source code in directory DIR. Usually
+ `configure' can determine that directory automatically.
+
+`--version'
+ Print the version of Autoconf used to generate the `configure'
+ script, and exit.
+
+`configure' also accepts some other, not widely useful, options.
+
diff --git a/INSTALL-cross b/INSTALL-cross
new file mode 100644
index 00000000..16ace324
--- /dev/null
+++ b/INSTALL-cross
@@ -0,0 +1,119 @@
+ === Hey, Emacs! This is -*- Text -*- !!! ===
+Last update 11 Apr 1996 by Michael I. Bushnell, p/BSG (mib@gnu.ai.mit.edu).
+
+
+These are instructions for building the Hurd as in cross-development
+environment. Unless you are building the Hurd on an already running
+Hurd system, you will need these directions to build the Hurd from any
+other kind of system. Even if you are using a Mach system (Lites,
+say) you will *STILL* need to follow these directions; this is still
+cross-compilation.
+
+
+
+I:
+
+First you must have GCC and binutils installed. We use GCC 2.7.2 and
+recent Cygnus binutils snapshots. You need to configure binutils and
+GCC for the i486-gnu target. In order to build the GNU C library for
+the Hurd, you will need gawk installed. You should install GCC and
+binutils as the instructions for these programs indicate. The Hurd
+makefiles depend on having them installed correctly as
+cross-development tools. Even if you are building the Hurd on a 486,
+even if it's running a different Mach-based OS, you are still cross
+compiling. Don't attempt to use tools that have been configured for
+something other than i486-gnu.
+
+Install things in /usr/local, as the Makefiles do by default. If you
+change $(prefix) when installing the cross-development tools, then
+random problems might happen. I cannot stress to highly that you are
+much better off doing things in the ordinary default way.
+
+
+II:
+
+You need space to "install" the compiled Hurd, its libraries, include
+files, and binaries that will run on the Hurd. In these instructions,
+we will refer to this as the "installation staging area". This will,
+more or less, be a suitable image to use as a Hurd root image when you
+are finished.
+
+This space needs to be accessible to the machine doing the
+cross-compilation, because the libc and include files that go in the
+Hurd's root filesystem are also the ones that are needed during
+cross-compilation.
+
+We strongly advise that this directory not be put in /usr/local. This
+will tend to cause confusion.
+
+If you followed the directions in (I) above, then in
+/usr/local/i486-gnu you already have a number of cross-development
+tools. (ar, ranlib, ld, as and so forth.) This is the place where
+the compiler looks for cross-development stuff. So now make two
+symlinks, named /usr/local/i486-gnu/include and
+/usr/local/i486-gnu/lib, and point them at foo/include and foo/lib,
+where `foo' is the name of you Hurd installation staging area. If you
+don't do this, you will lose. Do it now.
+
+
+III:
+
+You should get MiG from the Utah mach4 distribution, and build it to
+cross compile. Set MIG appropriately in Maketools (usually to
+"i486-gnu-mig"). Install it as /usr/local/i486-gnu/bin/mig, install
+migcom as /usr/local/i486-gnu/lib/migcom. (Note that the last
+pathname, because of the symlink you made in step II, is actually
+somewhere in the Hurd installation staging area directory. This is
+strictly wrong, because the running Hurd won't be able to use that
+migcom. Don't worry, just remember when you boot the Hurd that this
+one program won't work quite right. We intend to fix this later.)
+
+
+IV:
+
+MAKE VERY SURE that gcc, for all Hurd work, does not use a gcc include
+directory with fixincludes processed files. Your special GCC include
+directory should have *only* GCC include files. GCC should do this by
+default, but you might want to check in
+/usr/local/lib/gcc-lib/i486-gnu/CCVERSION/include to make sure.
+
+
+V:
+
+Now, make the GNU C library. Please read its own installation
+instructions, but here is a brief summary.
+
+Configure the GNU library with a command like:
+
+configure i486-gnu --with-mach=FOO --with-hurd=BAR --prefix=BAZ
+
+FOO should be the top level source directory of your Mach source.
+BAR should be the top level Hurd source directory.
+BAZ should be the installation staging area you have chosen.
+
+Build and install the library with `make install'.
+
+
+VI:
+
+Configure the Hurd with a command like:
+
+"CC=gcc -b i486-gnu" configure i486-gnu --prefix=BAZ
+
+BAZ is, again, the name of your installation staging area.
+
+Build and install the Hurd with `make install'.
+
+
+VII:
+
+Now in your Hurd staging area are the complete binaries for the Hurd
+and its programs, and the C library and its associated programs. You
+will want binaries for other programs too, of course--for example, you
+have no shell yet. In general, you can build most GNU packages
+without too much hassle using your cross compilers. In this way you
+can build up as much of a binary distribution as you like.
+
+See the file `INSTALL-binary' for instructions on running your new
+binaries.
+
diff --git a/NEWS b/NEWS
new file mode 100644
index 00000000..fe2f2649
--- /dev/null
+++ b/NEWS
@@ -0,0 +1,575 @@
+-*- Text -*-
+
+April 15, 1995
+
+It's hard to summarize, so much has happened.
+
+We have NFS, a network, and jillions of stuff. Basically things just
+work. Except for a jillion little nits, this is very nearly an alpha
+release. Not quite, but nearly.
+
+
+
+
+The `boot' program now accepts an option ``-D DIR'' which specifies a
+directory prefix for the file names given in the boot script (hurd.boot).
+So the way to boot is now:
+ $ boot.a -D .../hurd-image hurd.boot sd0a
+
+
+October 5, 1995
+
+The Hurd distribution now uses a `configure' script in the standard GNU
+style. As with other GNU packages, you can configure in the source
+directory or in a separate build directory (though not both with the same
+source directory); all you should need to do is `configure i386-gnu'. The
+Hurd does not compile in any file names using $(prefix), so you can specify
+the prefix where you will install things with the `--prefix' option; e.g.,
+`configure --prefix=/gd4/hurdinst i386-gnu'. You should no longer need to
+edit any makefiles. You can choose the tool names by setting variables in
+the environment when running configure (CC, LD, AR, RANLIB, OBJCOPY, MIG);
+the default is to search your $PATH for HOST-TOOL (e.g. i386-gnu-gcc), and
+failing that just TOOL (e.g. gcc), so you will win automagically if you
+simply use the same host alias in the `configure' command line as you used
+for the target alias to configure gcc and binutils (i.e. i386-gnu).
+
+The file_truncate RPC (in fs.defs) has been renamed file_set_size and
+now is expected to extend files as well as truncate them, in the
+manner of recent BSD releases' ftruncate. file_pathconf has been
+moved from fs.defs to io.defs and renamed io_pathconf. The `core'
+interface has been renamed `crash'.
+
+We are now using a new terminal driver that is multi-threaded. It is
+also much more simple internally than the older version, but otherwise
+supports no new features.
+
+Everything is now dynamically linked except the bootstrap filesystem. Any
+old statically linked binaries should be replaced. WARNING: In the next
+snapshot changes in the exec server may prevent older statically linked
+binaries from running.
+
+The exec server by default now only supports ELF; if you have older
+a.out binaries you want to run, you need to reenable BFD support in
+the exec Makefile. (Old a.out binaries should be replaced anyhow,
+with dynamically linked ELF binaries, for the reasons in described in
+the warning above.)
+
+The bootstrap hack in the directory boot now understands boot scripts;
+this kind of boot script will also be used by an upcoming release of
+Mach4. Also, because the exec server is now dynamically linked, it is
+necessary to install the exec server itself on the Hurd partition (in
+/hurd/exec); that was not necessary before, so it is possible that old
+working Hurd partitions might not have it.
+
+Some problems and trivial bugs in fsck are fixed.
+
+A few bugs in libdiskfs, libpipe, pflocal, and trans were fixed of no
+particular consequence.
+
+Shutdown of filesystems now works reliably and safely.
+
+Libports now provides stubs to do the normal thing for the interrupt and
+notify interfaces. Because of the interruption semantic, cthreads
+multiplexing of multiple cthreads onto fewer kernel threads can no longer
+be used; this means that ports_manage_port_operations_multithread no longer
+pays attention to the WIRE_CTHREADS flag.
+
+Cthreads now supports an implication semantic for conditions; this
+enables a condition variable to be created which is the disjunction of
+other condition variables.
+
+Trivfs now supports errors and blocking on open much better.
+
+A rare but serious bug in the pager has been fixed; along with this,
+another minor deficiency in the kernel has become apparent.
+
+The Makefiles are more generic and deal with shared libraries better.
+
+A serious bug has been fixed in ext2fs.
+
+
+
+July 23, 1995
+
+Shared libraries now work; use -static to link programs and avoid the
+shared libraries. The Hurd programs are normally built static; this
+will probably change soon.
+
+The ext2fs server now works, as do the tools to manipulate ext2fs
+filesystems. A snapshot of the tools will be made soon under separate
+cover. Many thanks to Ted Ts'o for his valuable work on the tools.
+
+Readers of the Makefiles will notice that we now generate dependencies
+automatically.
+
+The old netserv library is gone.
+
+The `boot' hack has been modified slightly to avoid the normalq libc startup
+files, because they no longer work with UX.
+
+Some small bugs have been fixed in the devio server.
+
+The ports library has been totally rewritten; new features permit
+servers to have greater control over thread RPC's and port creation.
+
+The fshelp library now does most of the work for translator
+interaction; it's simpler now too. Filesystems have much less work to
+do; the relevant code in libdiskfs is now understanble instead of
+unparseable chaos.
+
+The ports library provides for timeouts; the diskfs library almost
+uses it, but because of a bug, it's disabled for now.
+
+Filesystems are now expected to sync themselves if necessary; the new
+fsys_set_options RPC provides for changeing (or cancelling) the sync
+intervale. The diskfs library does this for you. The update program
+is no longer necessary.
+
+A small bug in the proc server has been hacked around; the real fix
+will come later.
+
+Many important bugs in the C library have been fixed since the last
+snapshot; perhaps all of them. ;-)
+
+
+
+June 6, 1995
+
+The Hurd has switched to using the ELF object file format instead of a.out.
+You will need a very recent snapshot of GCC and binutils (we are using the
+950606 versions); the `i386-gnu' configuration now uses ELF, we are dumping
+a.out entirely.
+
+The exec server now understands the ELF format directly (not through BFD),
+because BFD has some deficiencies in its treatment of ELF. The direct
+support for a.out has been ripped out completely. The exec server can
+still support BFD as an optional addition, if compiled with -DBFD; this is
+now the only way to run a.out executables. But if you only want to run new
+ELF binaries, then you can omit -DBFD and needn't bother building the BFD
+library to build the Hurd. The support for gzip'd executables is now
+conditional on -DGZIP; it adds a pretty small amount of code. Our
+makefiles use both -DGZIP and -DBFD by default; edit exec/Makefile if you
+wnat to omit BFD or gzip support. (Probably soon we will omit -DBFD by
+default because it will make the exec server much smaller, but we just
+switched and still have run a.out binaries lying around we'd like to
+continue being able to run.)
+
+Because everything is now in ELF, the procedure to create an executable of
+the `boot' program that can run on UX is rather hairy. Do `make boot.a' in
+the boot directory and run `boot/boot.a', which is an a.out executable.
+`boot/boot' is a weirdo ELF executable that UX cannot understand.
+
+The startup sequence has changed; the exec server image is no longer
+embedded in the filesystem image. The `boot' program loads both the
+filesystem and the exec server into separate tasks and runs the filesystem,
+passing it the task port of the exec server, which it starts running when
+it's ready for it. This closey approximates the eventual plan for booting
+the system, wherein the boot loader will load the multiple program files as
+well as the kernel, and the kernel will set up the two tasks. However,
+changes are needed in the Mach bootstrap process to read ELF binaries and
+to start multiple servers, so for the moment native booting is broken.
+
+April 12, 1995
+
+Many bugfixes and changes. Now includes a fancy ps, settrans, and
+showtrans; separate translators for all the programs in /dev (and a
+MAKEDEV script). Also the provisional source for network servers and
+some other snippets of code are now being distributed. The trivfs
+library is now multithreaded.
+
+The old dev.trim is still being distributed, but you shouldn't use it.
+
+A serious bug that broke the filesystem's state after enough exec
+failures (of the bad format sort) happen. A deadlock or two was also
+found and fixed.
+
+December 13, 1994
+
+The exec server now recognizes gzip'd binaries and uncompresses them into
+memory to execute them. (This has allowed a useful number of binaries to
+fit on a 1.44MB floppy.)
+
+November 24, 1994:
+
+Program changes:
+
+term could hang in delivery of terminal signals; fixed.
+
+pipes now handles io_select.
+
+These fixes allow GNU Emacs to work under the Hurd, with subprocesses.
+
+November 11, 1994:
+
+Structural changes:
+
+Our sources are now under RCS. That shouldn't affect you at all,
+except that the file in the distribution will now be mostly mode 0444
+by default.
+
+
+Interface changes:
+
+`dealloc' flags have been added to many MiG interfaces broadly to fix
+a class of bugs.
+
+
+Library changes:
+
+Synchronous locks were hanging in some cases; to avoid it for now,
+they are never done at all. (Of course, this is really a bug that
+needs fixed; the current change is purely for the sake of running the
+system.)
+
+Some bugs in translator startup in libfshelp have been fixed.
+
+Bootstrapping in libdiskfs is cleared up. A bug in io_read that cause
+a crash if you gave an offset past the file size has been fixed.
+Non-root filesystems can now contact the execserver.
+
+
+Program changes:
+
+The `boot' hack can now start the first task in one of three ways: the
+way it was before, which is pretty Hurd-ish; just like the kernel
+starts the first task; and just like CMU's `boostrap' user program
+starts the CMU multiserver. Also, `boot' always passes a -f flag so
+that other programs can no we aren't really running native.
+
+The execserver now registers itself properly on /servers/exec and can
+thus be used by non-bootstrap filesystems.
+
+Init uses symbolic names for /bin/sh and /dev/console rather than
+hardcoded strings. The STANDALONE macro is gone; the behavior is the
+same but depends on the presence or absence of -f in the boot flags.
+
+Some minor bugs in proc have been fixed.
+
+The terminal driver now sends SIGWINCH properly. Changing to and from
+ICANON now moves the terminal input queues around properly.
+
+The filesystem now uses one pager to map the disk and little pagers to
+map files. Some hair is new to keep data from showing up in both
+pagers; generally the code is much simpler and cleaner now. (Faster,
+too.) The DT_* type information is currently unused due to an
+implementation difficulty. Some workarounds have been installed to
+avoid some kernel bugs.
+
+Large writes to the pipes server used to crash it; they don't any
+longer.
+
+The /dev server now has hardcoded into it more disks and it's easier
+to add more yourself. Also work around a kernel bug.
+
+New utilities: clri, sync, halt, reboot. The output of ps has been
+cleaned up a little.
+
+Fsck has been rewritten; there are still bugs in creating directories.
+(That code is only used if /lost+found is absent, so it's still
+useful.) The old version is renamed to bsdfsck.
+
+
+
+
+September 8, 1994:
+
+Structural changes:
+
+No significant structural changes have been made.
+
+
+Interface changes:
+
+term.defs has a new RPC `termctty_open_terminal', necessary for
+implementing /dev/tty.
+
+The filesystem lookup retry mechanism has been altered slightly.
+FS_RETRY_NONE is gone. If the retry pathname is empty, then no retry
+is necessary, and the returned port should be used, after
+reauthenticating it if FS_RETRY_REAUTH was set. Uniformly Hurd
+servers attach no special meaning to leading / in filenames, the
+result is that leading / (to Hurd servers) is a NOP.
+
+The authentication protocol now passes a second port for rendezvous
+rather than an int; this cleans up a slight security hole. The I/O
+and proc protocols have been changed accordingly.
+
+The args to file_set_translator have been cleaned up.
+
+All routines that used to say `path' no longer do; in GNU we always
+call these filenames.
+
+
+Library changes:
+
+libdiskfs and libfshelp now do passive translator startup properly.
+
+Setuid execution is now done by libdiskfs.
+
+A little work has been done in libpager towards implementing a default
+pager, bit it's not complete yet.
+
+
+Program changes:
+
+A braino in the auth server was fixed, and it uses the new auth
+protocol.
+
+The boot program no longer spins; it uses multiple threads. It also
+takes nice command line args. ufs and init only pause for debugger
+attach if you give boot the -d flag. Init now expects passive
+translators to be set for /dev and it looks prettier.
+
+The kludgy dev server now also works for (1) disk.
+
+Some exec server bugs in EXEC_NEWTASK were fixed.
+
+There is now a port of fsck, and two new programs: settrans and
+opendisk.
+
+The proc server now has a better prime number generator, and some
+small bugs have been fixed.
+
+The terminal driver now does job control and other signals correctly.
+
+Some minor improvements have been made in ufs.
+
+
+
+
+August 8, 1994:
+
+Structural changes:
+
+Makefiles have been vastly improved and are simpler. The programs
+`su', `ps', and `sh' have been moved from separate dirs into `utils';
+the programs `symlink' and `ifsock' have been moved into `trans'.
+
+Several changes were made to GCC use. You should definitely get GCC
+version 2.6.0 now. Version 2.6.1 will have distributed the proper
+`specs' file for the i386-gnu target, but it isn't quite ready yet, so
+you still have to copy hurd/gcc-specs into
+gcc-lib/i386-gnu/2.6.0/specs.
+
+
+Interface changes:
+
+The tioctl.defs suite is complete now.
+
+INTR RPC's have been changed; individual RPC's are no longer marked
+INTR. Rather, entire interfaces are marked `INTR_INTERFACE' if they
+conform to the library's signalling/interruption expectations.
+
+There is a new magical retry type (for dir_pathtrans and fsys_getroot)
+called `machtype' and a new one `/'; the former is for @sys tweaks and
+the latter cleans up the retry of root-based symlinks a bit.
+
+There is a new interface `login.defs'.
+
+The "dotdot node" is no longer passed at fsys_startup time; instead,
+it is passed by fsys_getroot.
+
+
+Library changes:
+
+The ports library now does death-timeouts for multi-threaded servers;
+it doesn't actually work right yet, however. Also the ports library
+has new features (soft vs. hard ports; no outstanding ports
+notifications) that enable server-death to be done cleanly. (I hope;
+libdiskfs and ufs haven't yet been changed to use it, so libports
+might not actually have the right facilities yet.)
+
+The translator startup routines in libfshelp have been vastly improved
+(so that they can actually be used).
+
+Numerous bugfixes in libdiskfs, particularly relating to translator
+usage. Use new magical retry type `/' when appropriate. Use new
+dotdot node protocol. O_FSYNC and O_NOATIME are now honored properly.
+Alternative methods of storing symlinks are now supported through new
+hooks.
+
+The new dotdot protocol is now used by libtrivfs. Also, users of the
+library are now able to set the atime and mtime when necessary.
+
+The special threads version of malloc has been placed back in
+libthreads now that the C library uses a Mach-safe version on its own.
+
+
+Program changes:
+
+The `boot' program no longer implements the tioctl interface now that
+the terminal driver works.
+
+A bug was fixed in the handling of pgrps in `proc'.
+
+Many bugfixes in term. The tioctl interface is now implemented. EOF
+processing is fixed; break characters now work right. Signals and
+interruption are now done correctly. VDISCARD works.
+
+Ufs has Some bigs fixed in dir.c. Filesystem upgraded to BSD 4.4.
+There are now some compatibility flags.
+
+New program dev.trim does a very minimal /dev (but doesn't work yet).
+New program dev is an initial (but poor) attempt at a real /dev.
+
+
+
+
+
+July 5, 1994:
+
+The Hurd now runs all the programs in the GNU fileutils, textutils,
+and shellutils distributions, with the exception of who. Most
+importantly it runs GNU Hello. Also, emacs works (with the kludgy
+`boot' terminal driver) and bash works.
+
+The simple pipes server works; it will be replaced eventually by the
+pflocal server (which isn't done yet). The terminal driver is limping
+but working. It doesn't support terminal ioctls yet. A minor bug in
+auth has been fixed. boot interprets more Hurd protocols; this was
+done to get emacs functioning. Some more-or-less serious bugs in exec
+were fixed; they were found by running emacs (a quite large executable
+indeed). At bootstrap time, init starts pipes and term itself;
+eventually these will be passive translators, but we don't want to
+write the new disk format until we're self-hosting or fsck and UX will
+get confused. The file proc/primes.c has been documented; thanks go
+to Jim Blandy. Some bugs in proc dealing with pgrp and wait were
+fixed; a nasty hash table bug was also fixed. The simple shell can do
+pipes. Several serious bugs in ufs were fixed dealing with extension
+of large files and writes of data not aligned on block boundaries.
+The ufs pager was over-serialized; that's been fixed. Directory
+lookups and modifications now use mapped I/O directly; this is an
+important speed-up. The structure of the pager lockes has been
+changed significantly. UFS now supports Mach copying mode
+MEMORY_OBJECT_COPY_DELAY; this significantly improves process startup
+time.
+
+Some minor changes have been made to several interfaces. The
+interface for fs.defs:dir_readdir has been totally changed. There are
+some new fs.defs interfaces: file_check_access, file_notice_changes,
+dir_notice_changes. The fsys.defs:fsys_getroot interface was changed
+to work correctly. process.defs:proc_setprocargs is renamed, and a
+fetch function proc_get_arg_locations is added. The ifsock.defs
+interface was simplified.
+
+Several bugs were fixed in libdiskfs. The new dir_readdir interface
+requires new support from format-specific code. Some race conditions
+have been fixed. dir-pathtrans.c now deals correctly with multiple
+slashes in a row. A new concept called "light references" allows
+pagers to remain active without preventing truncate-on-nolinks from
+working right. New interfaces in fs.defs are implemented (except
+file_notice_changes). Active translator usage has been fixed to work
+correctly, but passive translators are still untested. libdiskfs now
+thinks it supports S_IFSOCK nodes, but that's untested (of course)
+because pflocal isn't done yet.
+
+The passive translator startup interface in libfshelp has been
+radically simplified. The pager library now lets other code set and
+changee the attributes on objects, synchronously if desired. An
+init/terminate race condition was fixed. The ports library now
+allows single-threaded users to work right (they didn't before). The
+trivfs library works; see the ifsock server for a simple example of
+its use. See term or pipes for more complex examples.
+
+There is a task list in the file `tasks'; let me know if you are
+interested in working on one of these.
+
+
+May 17, 1994:
+
+The Hurd now runs all the programs in the GNU fileutils and textutils
+distributions. All the programs in shellutils run normally except
+who, false, groups, nohup, true, and nice. We can't tell if tty is
+working right because the necessary support isn't set up (so it just
+prints `not a tty'. Some minor filesystem bugs have been fixed,
+including several brainos in disk allocation and total lossage in
+symlink interpretation. No bugs are now known.
+
+The library now supports signals; the program `timertest' is one test
+program we've used.
+
+All the core servers register their version with proc and register
+themselves as essential tasks with init. This enables proc to compute
+proper uname version strings and enables init to crash the system if
+one of the core servers dies.
+
+Boot is set up with a special hack to detect the RPC's that emacs uses
+to go into and out of raw mode; this will hopefully enable us to run
+emacs soon.
+
+There is a kludgy server called `pipes' (not yet completed) which
+implements just those parts of the local-domain socket server that the
+library uses in implementing the `pipe' function. This will enable us
+to have a real shell somewhat before needing the local domain socket
+server.
+
+More work on trivfs has happened; this will be needed by pipes.
+
+Cthreads is now in the Hurd distribution; this will make it much
+easier to install. The GNU C library depends on some changes we have
+made to this version of C threads and will not work with other
+versions you might have. (Several files in other versions of CMU
+Cthreads are not in this distibution [notably spin locks]; those are
+now in the GNU C library.)
+
+The installation hints in README have changed considerably; read them
+again.
+
+I'm now keeping ChangeLogs; you can examine them for more detailed
+information.
+
+
+
+April 5, 1994:
+
+The Hurd now bootstraps. Auth and proc start successfully; init
+prints "Init has completed" where it would run the shell.
+
+There are the beginnings of some documentation in the new doc
+directory.
+
+
+
+March 25, 1994:
+
+The Makefiles now are set up for cross-compilation; see README and the
+comments in Makeconf and Maketools for more information.
+
+The new diskfs library is complete. The filesystem using it runs as
+well as the previous version. Interested folk: please examine the
+diskfs interface, and see if it can be used for your favorite
+filesystem; I'd like it to be as general as possible.
+
+The proc server and auth servers link completely but have not been
+tested. The init.trim directory holds a lightweight version of init
+suitable for use before the C library support for file descriptors,
+exec, and so forth works; this version of init compiles and links.
+The primary effort right now is booting init, proc, and auth.
+
+Work has been suspended on tmpfs for the time being, it not being
+necessary for a running system. Some new FS calls have been added,
+notably dir_mkfile.
+
+
+Feb 1, 1994:
+
+Much filesystem code has been split out into new libraries, most
+notably, libpager, which now contains the implementation of the
+complex multi-threaded pager previously in the filesystem.
+
+libdiskfs will continue this process, with everything related to
+filesystems based on disks (or other real substrates), but format
+independent. libfshelp will have routines for starting translators,
+keeping track of flock, and so forth; it will be useful for any
+implementor of the fs protocol. ufs currently does not use either of
+these, but will when they are done.
+
+tmpfs and init.trim are in progress. tmpfs will be memory-only for
+things like /tmp, and is currently waiting for the fshelp library to
+be finished. init.trim will be a scaled down init, useful for testing
+bootstrapping before there is enough library support to run the real
+init. Currently this is waiting on fixing some crucial ld bugs.
+(When those are fixed, work will begin in earnest on bootstrapping
+auth, proc, and init.)
+
+
diff --git a/README b/README
new file mode 100644
index 00000000..49200c67
--- /dev/null
+++ b/README
@@ -0,0 +1,23 @@
+-*- Text -*-
+GNU Hurd version 0.0.
+
+
+This is the Hurd. Welcome.
+
+For instructions on compiling and installing the GNU Hurd from an
+already running Hurd system, see the file `INSTALL'.
+
+It is possible to cross-build the Hurd; the file INSTALL-cross
+contains some past instructions for doing so, but it's too much
+trouble to maintain them and make them easier. Your best bet is to
+start with a running Hurd system already.
+
+Please note that this directory also contains a fair amount of
+not-yet-working code. The makefiles build only the working code by
+default.
+
+The GNU Hurd is free software. All of it, including the libraries in
+this distribution, is covered by the GNU General Public License, found
+in the file COPYING.
+
+
diff --git a/SOURCES.0.0 b/SOURCES.0.0
new file mode 100644
index 00000000..a601ee19
--- /dev/null
+++ b/SOURCES.0.0
@@ -0,0 +1,196 @@
+Sources for binaries in Hurd version 0.0.
+
+STILL TO CATEGORIZE: XXX
+* fileutils (3.13) [rebuild for df after libc install]
+* gperf (cperf 2.1a) [hacked src/Makefile and src/stderr.c slightly]
+ [substitute with libg++ version?]
+libc
+mach
+
+
+
+The following packages were built from the sources of the indicated
+version in ftp://prep.gnu.ai.edu/pub.gnu according to the provided
+instructions without modification:
+
+* autoconf (2.10)
+* automake (1.0)
+* bc (1.03)
+* binutils (2.7)
+* bison (1.25)
+* cpio (2.4.2)
+* cvs (1.8.1, in cvs-1.8.tar.gz)
+* diffutils (2.7)
+* doschk (1.1)
+* ed (0.2)
+* emacs lisp manual (19-2.4)
+* flex (2.5.3)
+* gawk (3.0.0)
+* gcal (1.01)
+* gcc (2.7.2)
+* gdbm (1.7.3)
+* gettext (0.10)
+* gmp (2.0.2)
+* grep (2.0)
+* hello (1.3)
+hurd (0.0)
+* indent (1.9.1)
+* inetutils (1.0)
+* less (320)
+* m4 (1.4)
+* miscfiles (1.0)
+* nvi (1.71)
+* ptx (0.4)
+* readline (2.0)
+* recode (3.4)
+* sed (2.05)
+* sharutils (4.2)
+* termcap (1.3) [manual only]
+* termutils (2.0)
+* textutils (1.19)
+* time (1.7)
+* wdiff (0.5)
+
+
+
+The following packages were built from the sources of the indicated
+version in ftp://prep.gnu.ai.mit.edu/pub/gnu according to the provided
+instructions, after making the indicated minor modifications:
+
+* emacs (19.31)
+ [comment out definition of tparam in src/terminfo.c.]
+ [add to src/s/gnu.h the following five lines]
+ #ifdef HAVE_LIBNCURSES
+ #define TERMINFO
+ #define LIBS_TERMCAP -lncurses
+ #endif
+ #define setpgrp(a,b) setpgrp()
+* findutils (4.1)
+ [Comment out decl of basename in defs.h and defn in util.c]
+* gzip (1.2.4)
+ [commented out basename from gzip.h and util.c]
+* ncurses (1.9.9e)
+ [In read_entry.c, change second arg of call to open from `0' to O_RDONLY]
+ [In lib_tparm.c:tparam, add the following before the call to tparam_internal]
+ if (!buffer)
+ buffer = malloc (256);
+* patch (2.1)
+ [comment out basename in backupfile.c.]
+* rcs (5.7)
+ [Put `#undef ED' before #define ED in conf.h.]
+ [Add `#define SYMLOOP_MAX 8' to conf.h.]
+* tar (1.11.8)
+ [add `strerror' to AC_CHECK_FUNCS in configure.in]
+* texinfo (3.7)
+ [info/terminal.c -- add `#define B9600 9600']
+
+
+
+
+The following were compiled from the sources found in
+ftp://prep.gnu.ai.mit.edu/pub/gnu/gnu-0.0/hurd-special-src:
+
+* bash (1.14.4 patchlevel 10, with some additional local bugfixes)
+e2fsprogs (e2fsprogs-0.5c-hurd1.tar.gz) [1.04 doesn't have hurd patches]
+serverboot
+* from
+(*) grub
+ [ Requires changes for ELF: avoid generating 16-bit relocations.
+ Requires other changes to deal with ELF; makefiles only work for
+ mach3-a.out object file format. ]
+* sh-utils (1.12m from alpha.gnu.ai.mit.edu; unmodified)
+* make (3.74.5 from alpha.gnu.ai.mit.edu; unmodified)
+gdb (Modified from Cygnus snapshot of 960526) [wait for Mach to get migcom]
+
+
+
+
+
+Give up:
+finger (1.37)
+mtools (3.0) [comment out decl of sys_errlist in sysincludes.h.]
+ [Uses of MAXPATHLEN]
+oleo (1.6) [utterly fails to build]
+gnuplot (3.5) [has old old version of readline]
+es (0.84 from ftp.white.toronto.edu)
+ (-DEVFD=1 -DGETGROUPS_USES_GID_T=1 -DREADLINE=1
+ -DUSE_SIGACTION=1 -DUSE_SIG_ATOMIC_T=1)
+ [ Errors for longjmp in access.c and parse errors besides]
+regex (0.12) [Expects TeX to be present]
+screen (3.7.1) [Wants utmpx.h]??
+ispell (3.1.20) [hacked for bison; builds zero-length dictionary]
+rx (1.0) [ wants `tsort' to configure ]
+perl (5.003) [configure script fails in shlib frobnication]
+
+
+Secondary:
+* from (from.tar.gz)
+X libraries
+X utilities
+TeX
+METAFONT
+libg++
+calc
+chess
+clisp
+csh
+dld
+gcl
+dejagnu
+elib
+elisp archive
+f2c
+ffcall
+g77
+fontutils
+ghostscript
+ghostview
+git
+gnugo
+graphics
+groff
+hp2xx
+hyperbole
+id-utils
+jacal
+lily
+mkisofs
+nethack (3.2.1)
+ [3.2.0 + nethack-3.2.0-3.2.1.patch
+ define BSD & linux, frob paths in config.h & unixconf.h & root Makefile
+ comment out declaration of random in system.h]
+nih classes
+oaklisp
+libobjects
+mm
+obst
+octave
+ [See ftp://ftp.che.wisc.edu/pub/octave/README-GCC-2.7.0]
+ [See ftp://ftp.che.wisc.edu/pub/octave/README-GCC-2.7.1]
+p2c
+pcl
+pine
+rc
+scheme
+shogi
+sipp
+smalltalk
+sneps
+superopt
+tile forth
+ucblogo
+uucp
+vh
+vm
+xboard
+xinfo
+xshogi
+
+
+Tertiary:
+X server
+ae
+cfengine
+enscript
+gnat
+mc
diff --git a/TODO b/TODO
new file mode 100644
index 00000000..f43eab0a
--- /dev/null
+++ b/TODO
@@ -0,0 +1,227 @@
+-*- Mode: Outline -*-
+
+Things to be done on Hurd, that we should probably not punt to a volunteer.
+
+See `tasks', the exported task list.
+
+* RMS dictates:
+** O_RDONLY==0
+** "user-friendly" naming scheme for /dev
+
+* Emacs M-x shell seems to start all the ptys.
+* Settle termcap v. curses with rms et. al.
+* Contents of =pending-changes.
+* Make sure all the pieces of the Hurd have adequate version stuff.
+* syslogify everything
+* fix root dependencies in filesystem, network, etc.
+* Profile things
+* Make for easier installation
+
+* Libraries
+
+** libmom work:
+*** Hack interface definitions so that args are mom-ish
+*** Change libports and libpager to be mom-ish
+*** Change servers to be mom-ish
+
+** libc:
+*** Version of tmpfile that takes a directory
+*** Hurd versions of tmpfile that don't create transient files
+*** flink
+*** make sure profiling works
+*** implement revoke once io_revoke is added.
+
+** libports:
+*** Get rid of general `uninibited-rpcs' mechanism in libports, & just
+ special-case interrupt_operation.
+
+** libstore:
+*** test it and make diskfs use it.
+
+** libfsserver/libnetfs:
+*** convert libnetfs to libfsserver
+
+** libpager:
+*** Put user-defined fns into a callback struct passed to pager_create.
+*** Make libpager paging interface able to read/write multiple pages at once.
+*** Check all users of pager-create.c to make sure they DTRT when it returns
+ null.
+
+** libshouldbeinlibc:
+*** Merge contents of libshouldbeinlibc that belong there into libc.
+ Rename the rest to libhurdutil or somesuch.
+*** debug linewrap.c (in libshouldbeinlibc temporarily)
+*** argp: finde some way to flag certain long options as only matching
+ exactly (add this as OPT_EXACT); use this on the built in option
+ --program-name.
+*** Rewrite argp to do its own parsing. Preferably, split up libc's
+ getopt into more primitive functions, which both argp and getopt
+ can call.
+
+
+** libdiskfs
+*** detect write-protected media and turn on diskfs_readonly
+*** Add the short-circuited-but-not-builtin translator startup code from
+ dir-lookup to fsys_getroot. Compare and match carefully these two
+ routines and then share common code.
+*** Handle dead name notifications on execserver ports.
+*** Deal correctly with setting the translators on /servers/exec.
+*** Implement file_notice_changes.
+*** Implement async I/O.
+*** Think of a way to have when-to-sync-nodes be more flexible so it can
+ be done right for each format.
+*** Check when-to-sync-nodes carefully against BSD 4.4 ufs implementation.
+*** Provide for MNT_SYNCHRONOUS, MNT_NOEXEC, MNT_NOSUID, MNT_NODEV, etc.
+*** Implement io_restrict_auth correctly.
+*** Use libstore.
+*** Use off_t correctly.
+*** Add a consistent message printing facility for filesystems to use
+ (syslog, but takes special care when the root file system?).
+*** Some of diskfs_readonly_changed in ufs/ext2fs should be in generic
+ routines.
+
+** libfshelp
+*** Put functions here to deal with directory and file change notifications?
+*** Translator startup should provide a more useful stdin/stdout than nothing?
+*** Add functions to do permission checking and change libdiskfs et. al.
+ to use them.
+
+** libpager
+*** Change interface to be more efficient with multi-page data-return calls.
+*** Remove pagers from portset if there are too many incoming requests to
+ avoid forking too many threads.
+*** flush functions don't actually force pending delayed copies. (and in
+ fact, they seem to block if a delayed copy is wired down)
+
+** libtrivfs
+*** Allow for read/write/exec to be passed down.
+*** Implement file_exec when appropriate.
+*** Provide for the visible owner, etc., to be held in command-line args
+ instead of the underlying node, when it's important.
+
+** libps
+*** Wizzior columnation (autosizing?)
+*** Make getters more robust.
+
+
+* Servers
+** write default pager
+** Implement goaway in all the servers that don't already have it.
+** (init) sleep on spinning gettys
+** Add calls to various servers to return interesting statistical information.
+** Test new-fifo & make it fifo.
+** Login/utmp?
+** fifos are flaky. ?? Details ??
+** pflocal: make peer addresses work?
+
+** proc:
+*** Add a version of proc_wait usable by non-parent processes, and use it in
+ gdb; maybe just a flag WNOREAP to proc_wait that doesn't reap and allows
+ anyone to use it.
+*** Add proc_get_tty() [returns tty opened with no flags], so that ps can be
+ non-suid.
+*** Remove hostname/hostid functions
+
+** pfinet
+*** Allow multiple pfinets to arp on the same ethernet interface for different
+ IP addresses.
+*** Register a shutdown notification to close TCP channels.
+
+** nfs
+*** Implement async I/O
+*** Finish work to turn on paging.
+*** Finish excl arg work in link and rename.
+
+** devio:
+*** Make a server (/servers/devio?) to share multiple devio nodes?
+*** Use libstore.
+*** Make block devices work again.
+*** MAKEDEV should be able to make physical terminal devs.
+*** Get rid of global DEVICE variable and use the trivfs control hack.
+*** Serverify, ala new-fifo.
+
+** ufs:
+*** Implement clustering, a la 4.4-lite sys/kern/vfs_cluster.c.
+*** Make file_get_storage_info work for files with indirect blocks.
+*** Optimizations:
+ pager.c/inode.c/libdiskfs count pager refs separately and then save
+ mappings in _diskfs_rdwr_internal and dir.c
+*** Problems with DT_* hack:
+**** Fix multiple-links DT_* bug.
+**** Deal with change of type which should update directory.
+**** Type is also wrong for translated nodes...
+*** Roland sez: ENOSPC detection flaky in ufs. Try write of >page,
+ non-page-multiple, when free space allows write size but not
+ round_page (write size).
+*** After using cp-dRuv to update lots of files to a ufs filesystem, sometimes
+ settrans -a says `Device Busy' if you subsequently attempt to shut it down.
+ (is this still true?)
+
+** ext2fs
+*** Support chflags/st_flags and convert to/from ext2 flags on disk.
+*** Try to write directories with 512-byte record boundaries.
+*** Maybe file_pager_write_page should be able to accurately reproduce holes...
+*** Add byte-swapping.
+
+** crash
+*** Write core files.
+
+** init
+*** SIGHUP and SIGQUIT don't seem to do the right thing.
+
+
+* Utilities
+** Write a real mount program.
+** settrans needs an option to make the active go away without using goaway.
+** Make id, et. al. work with no/multiple uids.
+** Make things work with the `nobody' mode bits: chmod, ls, ...
+** Make things work better with translators, e.g., tar...
+** Fix bash to turn on interrupts around syscalls more generally,
+ especially chdir.
+** Make su work.
+** Bug: `hostname' command with no /etc/hostname hangs the system with disk light going.
+** talk doesn't work
+** login: Make --retry work correctly when invoked via a suid shell
+ script by other than root (it doesn't now if the script specifies
+ --retry="$0" because the exec server will use /dev/fd/N for name,
+ and child_lookup() doesn't supply more than fds 0-2).
+
+
+** ps:
+*** ps should timeout quickly (one second?) on non-responsive message ports.
+*** --help output is wrong (probably line_wrap_point is not synced
+ with stream).
+*** help displays for: stat letters, format specs.
+*** Add head/tail options
+
+** gdb:
+*** Add various mach convenience features (vminfo, &c).
+*** Be even more vigilant about noticing new threads. In particular:
+**** For mach-indep thread commands, before validating against
+ internal thread list.
+*** read core files
+
+** nfsd -- fix remaining bugs
+*** Add necessary support to filesystems
+
+** fsck -- zero-length directories and attachment into lost+found still
+ don't work.
+
+
+* Mach:
+** Have some analogue of /dev/klog that syslogd can get kernel messages from
+ (maybe there is already?); the boot file system, and other people deeming
+ it too risk to attempt to contact syslogd can use it too?
+** Add a startup timestamp to tasks, and have some way of fetching it.
+
+
+* TODO for version 0.0:
+
+** Bug: GDB as non-root
+** Compile released libc.
+** Compile released utilities. (See SOURCES-0.0)
+** Make serverboot source tar and build instructions.
+** Deal with crypt
+** Relink everything after version numbered libc is installed
+** Debug ext2fs
+** Find fsck system hang
diff --git a/boot/frank1.ld b/boot/frank1.ld
new file mode 100644
index 00000000..9de827ae
--- /dev/null
+++ b/boot/frank1.ld
@@ -0,0 +1,94 @@
+OUTPUT_FORMAT("elf32-i386", "elf32-i386",
+ "elf32-i386")
+OUTPUT_ARCH(i386)
+ENTRY(_start)
+ SEARCH_DIR(/usr/local/i386-gnuelf/lib);
+/* Do we need any of these for elf?
+ __DYNAMIC = 0; */
+SECTIONS
+{
+ /* Read-only sections, merged into text segment: */
+ . = 0x10020;
+ .text :
+ {
+ *(.text)
+ *(.interp)
+ *(.hash)
+ *(.dynsym)
+ *(.dynstr)
+ *(.rel.text)
+ *(.rela.text)
+ *(.rel.data)
+ *(.rela.data)
+ *(.rel.rodata)
+ *(.rela.rodata)
+ *(.rel.got)
+ *(.rela.got)
+ *(.rel.ctors)
+ *(.rela.ctors)
+ *(.rel.dtors)
+ *(.rela.dtors)
+ *(.rel.init)
+ *(.rela.init)
+ *(.rel.fini)
+ *(.rela.fini)
+ *(.rel.bss)
+ *(.rela.bss)
+ *(.rel.plt)
+ *(.rela.plt)
+ *(.init)
+ *(.plt)
+ /* .gnu.warning sections are handled specially by elf32.em. */
+ *(.gnu.warning)
+ *(.fini)
+ *(.rodata)
+ *(.rodata1)
+ _etext = .;
+ PROVIDE (etext = .);
+ . = ALIGN(0x1000);
+ } =0x9090
+ . = ALIGN(0x1000);
+ .data :
+ {
+ *(.data)
+ CONSTRUCTORS
+
+ *(.data1)
+ *(.ctors)
+ *(.dtors)
+ *(.got.plt) *(.got)
+ *(.dynamic)
+ /* We want the small data sections together, so single-instruction offsets
+ can access them all, and initialized data all before uninitialized, so
+ we can shorten the on-disk segment size. */
+ *(.sdata)
+ _edata = .;
+ PROVIDE (edata = .);
+ . = ALIGN(0x10);
+}
+ __bss_start = .;
+ .bss :
+ {
+ *(.sbss) *(.scommon)
+ *(.dynbss)
+ *(.bss)
+ *(COMMON)
+ _end = ALIGN(4) ;
+ PROVIDE (end = ALIGN(4));
+ }
+ /* These are needed for ELF backends which have not yet been
+ converted to the new style linker. */
+ .stab 0 : { *(.stab) }
+ .stabstr 0 : { *(.stabstr) }
+ /* DWARF debug sections.
+ Symbols in the .debug DWARF section are relative to the beginning of the
+ section so we begin .debug at 0. It's not clear yet what needs to happen
+ for the others. */
+ .debug 0 : { *(.debug) }
+ .debug_srcinfo 0 : { *(.debug_srcinfo) }
+ .debug_aranges 0 : { *(.debug_aranges) }
+ .debug_pubnames 0 : { *(.debug_pubnames) }
+ .debug_sfnames 0 : { *(.debug_sfnames) }
+ .line 0 : { *(.line) }
+ /* These must appear regardless of . */
+}
diff --git a/boot/frankemul.ld b/boot/frankemul.ld
new file mode 100644
index 00000000..413953ef
--- /dev/null
+++ b/boot/frankemul.ld
@@ -0,0 +1,107 @@
+OUTPUT_FORMAT("elf32-i386", "elf32-i386",
+ "elf32-i386")
+OUTPUT_ARCH(i386)
+ENTRY(_start)
+ SEARCH_DIR(/usr/local/i386-gnuelf/lib);
+/* Do we need any of these for elf?
+ __DYNAMIC = 0; */
+SECTIONS
+{
+ /* Read-only sections, merged into text segment: */
+ . = 0x10020;
+ .text :
+ {
+ *(.text)
+ *(.interp)
+ *(.hash)
+ *(.dynsym)
+ *(.dynstr)
+ *(.rel.text)
+ *(.rela.text)
+ *(.rel.data)
+ *(.rela.data)
+ *(.rel.rodata)
+ *(.rela.rodata)
+ *(.rel.got)
+ *(.rela.got)
+ *(.rel.ctors)
+ *(.rela.ctors)
+ *(.rel.dtors)
+ *(.rela.dtors)
+ *(.rel.init)
+ *(.rela.init)
+ *(.rel.fini)
+ *(.rela.fini)
+ *(.rel.bss)
+ *(.rela.bss)
+ *(.rel.plt)
+ *(.rela.plt)
+ *(.init)
+ *(.plt)
+ /* .gnu.warning sections are handled specially by elf32.em. */
+ *(.gnu.warning)
+ *(.fini)
+ *(.rodata)
+ *(.rodata1)
+*(_hurd_ioctl_handler_lists)
+*(_hurd_pgrp_changed_hook)
+*(_hurd_fork_locks)
+*(_hurd_subinit)
+*(__libc_atexit)
+*(_hurd_fd_subinit)
+*(_hurd_preinit_hook)
+*(_hurd_fork_child_hook)
+*(_hurd_fork_parent_hook)
+*(_hurd_fork_prepare_hook)
+*(_hurd_reauth_hook)
+*(_hurd_proc_subinit)
+*(__libc_subinit)
+ _etext = .;
+ PROVIDE (etext = .);
+ . = ALIGN(0x1000);
+ } =0x9090
+ . = ALIGN(0x1000);
+ .data :
+ {
+ *(.data)
+ CONSTRUCTORS
+
+ *(.data1)
+ *(.ctors)
+ *(.dtors)
+ *(.got.plt) *(.got)
+ *(.dynamic)
+ /* We want the small data sections together, so single-instruction offsets
+ can access them all, and initialized data all before uninitialized, so
+ we can shorten the on-disk segment size. */
+ *(.sdata)
+ _edata = .;
+ PROVIDE (edata = .);
+ . = ALIGN(0x10);
+}
+ __bss_start = .;
+ .bss :
+ {
+ *(.sbss) *(.scommon)
+ *(.dynbss)
+ *(.bss)
+ *(COMMON)
+ _end = ALIGN(4) ;
+ PROVIDE (end = ALIGN(4));
+ }
+ /* These are needed for ELF backends which have not yet been
+ converted to the new style linker. */
+ .stab 0 : { *(.stab) }
+ .stabstr 0 : { *(.stabstr) }
+ /* DWARF debug sections.
+ Symbols in the .debug DWARF section are relative to the beginning of the
+ section so we begin .debug at 0. It's not clear yet what needs to happen
+ for the others. */
+ .debug 0 : { *(.debug) }
+ .debug_srcinfo 0 : { *(.debug_srcinfo) }
+ .debug_aranges 0 : { *(.debug_aranges) }
+ .debug_pubnames 0 : { *(.debug_pubnames) }
+ .debug_sfnames 0 : { *(.debug_sfnames) }
+ .line 0 : { *(.line) }
+ /* These must appear regardless of . */
+}
diff --git a/exec/core.c b/exec/core.c
new file mode 100644
index 00000000..6d685a23
--- /dev/null
+++ b/exec/core.c
@@ -0,0 +1,264 @@
+/* GNU Hurd standard core server.
+ Copyright (C) 1992 Free Software Foundation, Inc.
+ Written by Roland McGrath.
+
+This file is part of the GNU Hurd.
+
+The GNU Hurd is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+The GNU Hurd is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with the GNU Hurd; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <hurd.h>
+#include "core_server.h"
+#include <bfd.h>
+#include <string.h>
+
+/* Uses nonexistent bfd function: */
+char *bfd_intuit_section_name (bfd_vma vma, bfd_size_type size,
+ flagword *flags);
+
+/* Object file format to write core files in. */
+static char *core_target = NULL;
+
+/* Dump a core from TASK into FILE.
+ SIGNO and SIGCODE indicate the signal that killed the process. */
+
+error_t
+core_dump_task (mach_port_t coreserver,
+ task_t task,
+ file_t file,
+ int signo, int sigcode,
+ const char *my_target)
+{
+ error_t err;
+
+ processor_set_name_t pset;
+ host_t host;
+ processor_set_basic_info_data_t pinfo;
+
+ thread_t *threads;
+ size_t nthreads;
+
+ vm_address_t addr;
+ vm_size_t size;
+ vm_prot_t prot, maxprot;
+ vm_inherit_t inherit;
+ boolean_t shared;
+ memory_object_name_t objname;
+ vm_offset_t offset;
+
+ bfd *bfd;
+ bfd_architecture arch;
+ bfd_machine machine;
+ asection *sec;
+
+ /* The task is suspended while we examine it.
+ In the case of a post-mortem dump, the only thread not suspended will
+ be the signal thread, which will be blocked waiting for this RPC to
+ return. But for gcore, threads might be running. And Leviticus
+ specifies that only suspended threads be thread_info'd, anyway. */
+ if (err = task_suspend (task))
+ goto lose;
+
+ /* Figure out what flavor of machine the task is on. */
+ if (err = task_get_assignment (task, &pset))
+ goto lose;
+ err = processor_set_info (pset, PROCESSOR_SET_BASIC_INFO, &host,
+ &pinfo, PROCESSOR_SET_BASIC_INFO_COUNT);
+ mach_port_deallocate (mach_task_self (), pset);
+ if (err)
+ goto lose;
+ err = bfd_mach_host_arch_mach (host, &arch, &machine);
+ mach_port_deallocate (mach_task_self (), host);
+ if (err)
+ goto lose;
+
+ /* Open the BFD. */
+ bfd = NULL;
+ {
+ FILE *f = fopenport (file, "w");
+ if (f == NULL)
+ {
+ err = errno;
+ goto lose;
+ }
+ bfd = bfd_openstream (f, my_target ?: core_target);
+ if (bfd == NULL)
+ {
+ err = errno;
+ (void) fclose (f);
+ errno = err;
+ goto bfdlose;
+ }
+ }
+
+ bfd_set_arch_mach (bfd, arch, machine);
+
+ /* XXX How are thread states stored in bfd? */
+ if (err = task_threads (task, &threads, &nthreads))
+ goto lose;
+
+ /* Create a BFD section to describe each contiguous chunk
+ of the task's address space with the same stats. */
+ sec = NULL;
+ addr = 0;
+ while (!vm_region (task, &addr, &size, &prot, &maxprot,
+ &inherit, &shared, &objname, &offset))
+ {
+ mach_port_deallocate (mach_task_self (), objname);
+
+ if (prot != VM_PROT_NONE)
+ {
+ flagword flags = SEC_NO_FLAGS;
+
+ if (!(prot & VM_PROT_WRITE))
+ flags |= SEC_READONLY;
+ if (!(prot & VM_PROT_EXECUTE))
+ flags |= SEC_DATA;
+
+ if (sec != NULL &&
+ (vm_address_t) (bfd_section_vma (bfd, sec) +
+ bfd_section_size (bfd, sec)) == addr &&
+ flags == (bfd_get_section_flags (bfd, sec) &
+ (SEC_READONLY|SEC_DATA)))
+ /* Coalesce with the previous section. */
+ bfd_set_section_size (bfd, sec,
+ bfd_section_size (bfd, sec) + size);
+ else
+ {
+ /* Make a new section (which might grow by
+ the next region being coalesced onto it). */
+ char *name = bfd_intuit_section_name (addr, size, &flags);
+ if (name == NULL)
+ {
+ /* No guess from BFD. */
+ if (asprintf (&name, "[%p,%p) %c%c%c",
+ (void *) addr, (void *) (addr + size),
+ (prot & VM_PROT_READ) ? 'r' : '-',
+ (prot & VM_PROT_WRITE) ? 'w' : '-',
+ (prot & VM_PROT_EXECUTE) ? 'x' : '-') == -1)
+ goto lose;
+ }
+ sec = bfd_make_section (name);
+ bfd_set_section_flags (bfd, sec, flags);
+ bfd_set_section_vma (bfd, sec, addr);
+ bfd_set_section_size (bfd, sec, size);
+ }
+ }
+ }
+
+ /* Write all the sections' data. */
+ for (sec = bfd->sections; sec != NULL; sec = sec->next)
+ {
+ void *data;
+ err = vm_read (task, bfd_section_vma (bfd, sec),
+ bfd_section_size (bfd, sec), &data);
+ if (err)
+ /* XXX What to do?
+ 1. lose
+ 2. remove this section
+ 3. mark this section as having ungettable contents (how?)
+ */
+ goto lose;
+ err = bfd_set_section_contents (bfd, sec, data, 0,
+ bfd_section_size (bfd, sec));
+ vm_deallocate (mach_task_self (), data, bfd_section_size (bfd, sec));
+ if (err)
+ goto bfdlose;
+ }
+
+ bfdlose:
+ switch (bfd_error)
+ {
+ case system_call_error:
+ err = errno;
+ break;
+
+ case no_memory:
+ err = ENOMEM;
+ break;
+
+ default:
+ err = EGRATUITOUS;
+ break;
+ }
+
+ lose:
+ if (bfd != NULL)
+ bfd_close (bfd);
+ else
+ mach_port_deallocate (mach_task_self (), file);
+ task_resume (task);
+ mach_port_deallocate (mach_task_self (), task);
+ return err;
+}
+
+error_t
+fsys_getroot (fsys_t fsys, idblock_t id, file_t realnode, file_t dotdot,
+ file_t *root)
+{
+ *root = core;
+ mach_port_deallocate (mach_task_self (), realnode);
+ mach_port_deallocate (mach_task_self (), dotdot);
+ return POSIX_SUCCESS;
+}
+
+mach_port_t request_portset;
+
+int
+request_server (mach_msg_header_t *inp,
+ mach_msg_header_t *outp)
+{
+ if (inp->msgh_local_port == fsys)
+ return fsys_server (inp, outp);
+ else if (inp->msgh_local_port == core)
+ return (core_server (inp, outp) ||
+ io_server (inp, outp) ||
+ fs_server (inp, outp));
+}
+
+int
+main (int argc, char **argv)
+{
+ error_t err;
+ fsys_t fsys;
+ mach_port_t boot, dotdot;
+
+ if ((err = mach_port_allocate (mach_task_self (),
+ MACH_PORT_RIGHT_RECEIVE, &fsys)) ||
+ (err = mach_port_allocate (mach_task_self (),
+ MACH_PORT_RIGHT_RECEIVE, &core)))
+ hurd_perror ("mach_port_allocate", err);
+ else if (err = task_get_bootstrap_port (mach_task_self (), &boot))
+ hurd_perror ("task_get_bootstrap_port", err);
+ else if (err = fsys_startup (boot, fsys, &realnode, &dotdot))
+ hurd_perror ("fsys_startup", err);
+ mach_port_deallocate (mach_task_self (), dotdot);
+
+ mach_port_allocate (mach_task_self (),
+ MACH_PORT_RIGHT_PORT_SET, &request_portset);
+
+ mach_port_move_member (mach_task_self (), fsys, request_portset);
+ mach_port_allocate (mach_task_self (), MACH_PORT_RIGHT_RECEIVE, &core);
+ mach_port_move_member (mach_task_self (), core, request_portset);
+
+ mach_port_mod_refs (mach_task_self (), realnode, MACH_PORT_RIGHT_SEND, 1);
+
+ core_target = argv[1];
+
+ do
+ err = mach_msg_server (request_server, vm_page_size, request_portset);
+ while (!err);
+ hurd_perror ("mach_msg_server", err);
+ return 1;
+}
diff --git a/exec/elfcore.c b/exec/elfcore.c
new file mode 100644
index 00000000..4388a135
--- /dev/null
+++ b/exec/elfcore.c
@@ -0,0 +1,100 @@
+{
+ processor_set_name_t pset;
+ host_t host;
+ processor_set_basic_info_data_t pinfo;
+
+ thread_t *threads;
+ size_t nthreads;
+
+ vm_address_t addr;
+ vm_size_t size;
+ vm_prot_t prot, maxprot;
+ vm_inherit_t inherit;
+ boolean_t shared;
+ memory_object_name_t objname;
+ vm_offset_t offset;
+
+ /* Figure out what flavor of machine the task is on. */
+ if (err = task_get_assignment (task, &pset))
+ goto lose;
+ err = processor_set_info (pset, PROCESSOR_SET_BASIC_INFO, &host,
+ &pinfo, PROCESSOR_SET_BASIC_INFO_COUNT);
+ mach_port_deallocate (mach_task_self (), pset);
+ if (err)
+ goto lose;
+ err = bfd_mach_host_arch_mach (host, &arch, &machine, &e_machine);
+ mach_port_deallocate (mach_task_self (), host);
+ if (err)
+ goto lose;
+
+ if (err = task_threads (task, &threads, &nthreads))
+ goto lose;
+
+ /* Create a BFD section to describe each contiguous chunk
+ of the task's address space with the same stats. */
+ sec = NULL;
+ addr = 0;
+ while (!vm_region (task, &addr, &size, &prot, &maxprot,
+ &inherit, &shared, &objname, &offset))
+ {
+ mach_port_deallocate (mach_task_self (), objname);
+
+ if (prot != VM_PROT_NONE)
+ {
+ flagword flags = SEC_NO_FLAGS;
+
+ if (!(prot & VM_PROT_WRITE))
+ flags |= SEC_READONLY;
+ if (!(prot & VM_PROT_EXECUTE))
+ flags |= SEC_DATA;
+
+ if (sec != NULL &&
+ (vm_address_t) (bfd_section_vma (bfd, sec) +
+ bfd_section_size (bfd, sec)) == addr &&
+ flags == (bfd_get_section_flags (bfd, sec) &
+ (SEC_READONLY|SEC_DATA)))
+ /* Coalesce with the previous section. */
+ bfd_set_section_size (bfd, sec,
+ bfd_section_size (bfd, sec) + size);
+ else
+ {
+ /* Make a new section (which might grow by
+ the next region being coalesced onto it). */
+ char *name = bfd_intuit_section_name (addr, size, &flags);
+ if (name == NULL)
+ {
+ /* No guess from BFD. */
+ if (asprintf (&name, "[%p,%p) %c%c%c",
+ (void *) addr, (void *) (addr + size),
+ (prot & VM_PROT_READ) ? 'r' : '-',
+ (prot & VM_PROT_WRITE) ? 'w' : '-',
+ (prot & VM_PROT_EXECUTE) ? 'x' : '-') == -1)
+ goto lose;
+ }
+ sec = bfd_make_section (name);
+ bfd_set_section_flags (bfd, sec, flags);
+ bfd_set_section_vma (bfd, sec, addr);
+ bfd_set_section_size (bfd, sec, size);
+ }
+ }
+ }
+
+ /* Write all the sections' data. */
+ for (sec = bfd->sections; sec != NULL; sec = sec->next)
+ {
+ void *data;
+ err = vm_read (task, bfd_section_vma (bfd, sec),
+ bfd_section_size (bfd, sec), &data);
+ if (err)
+ /* XXX What to do?
+ 1. lose
+ 2. remove this section
+ 3. mark this section as having ungettable contents (how?)
+ */
+ goto lose;
+ err = bfd_set_section_contents (bfd, sec, data, 0,
+ bfd_section_size (bfd, sec));
+ vm_deallocate (mach_task_self (), data, bfd_section_size (bfd, sec));
+ if (err)
+ goto bfdlose;
+ }
diff --git a/exec/exectrans.c b/exec/exectrans.c
new file mode 100644
index 00000000..59c9cdf2
--- /dev/null
+++ b/exec/exectrans.c
@@ -0,0 +1,81 @@
+
+#include <stdio.h>
+#include <getopt.h>
+#include <error.h>
+#include <sys/stat.h>
+
+#include <hurd.h>
+#include <hurd/trivfs.h>
+
+
+/* Where to put the service ports. */
+static struct port_bucket *port_bucket;
+
+/* Trivfs hooks. */
+int trivfs_fstype = FSTYPE_MISC;
+int trivfs_fsid = 0;
+int trivfs_support_read = 1;
+int trivfs_support_write = 1;
+int trivfs_support_exec = 1;
+int trivfs_allow_open = O_READ|O_WRITE|O_EXEC;
+
+struct port_class *trivfs_protid_portclasses[1];
+struct port_class *trivfs_cntl_portclasses[1];
+int trivfs_protid_nportclasses = 1;
+int trivfs_cntl_nportclasses = 1;
+
+
+static int
+exec_demuxer (mach_msg_header_t *inp, mach_msg_header_t *outp)
+{
+ extern int exec_server (mach_msg_header_t *inp, mach_msg_header_t *outp);
+ return exec_server (inp, outp) || trivfs_demuxer (inp, outp);
+}
+
+void
+trivfs_modify_stat (struct trivfs_protid *cred, struct stat *st)
+{
+ st->st_fstype = FSTYPE_MISC;
+}
+
+error_t
+trivfs_goaway (struct trivfs_control *fsys, int flags)
+{
+ int count;
+
+ /* Stop new requests. */
+ ports_inhibit_class_rpcs (trivfs_cntl_portclasses[0]);
+ ports_inhibit_class_rpcs (trivfs_protid_portclasses[0]);
+
+ /* Are there any extant user ports for the /servers/exec file? */
+ count = ports_count_class (trivfs_protid_portclasses[0]);
+ if (count == 0 || (flags & FSYS_GOAWAY_FORCE))
+ {
+ /* No users. Disconnect from the filesystem. */
+ mach_port_deallocate (mach_task_self (), fsys->underlying);
+
+ /* Are there remaining exec_startup RPCs to answer? */
+ count = ports_count_class (execboot_portclass);
+ if (count == 0)
+ /* Nope. We got no reason to live. */
+ exit (0);
+
+ /* Continue servicing tasks starting up. */
+ ports_enable_class (execboot_portclass);
+
+ /* No more communication with the parent filesystem. */
+ ports_destroy_right (fsys);
+ going_down = 1;
+
+ return 0;
+ }
+ else
+ {
+ /* We won't go away, so start things going again... */
+ ports_enable_class (trivfs_protid_portclasses[0]);
+ ports_resume_class_rpcs (trivfs_cntl_portclasses[0]);
+ ports_resume_class_rpcs (trivfs_protid_portclasses[0]);
+
+ return EBUSY;
+ }
+}
diff --git a/exec/gcore.c b/exec/gcore.c
new file mode 100644
index 00000000..7343516c
--- /dev/null
+++ b/exec/gcore.c
@@ -0,0 +1,88 @@
+/* `gcore' for GNU Hurd.
+ Copyright (C) 1992 Free Software Foundation
+ Written by Roland McGrath.
+
+This file is part of the GNU Hurd.
+
+The GNU Hurd is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+The GNU Hurd is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with the GNU Hurd; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <hurd.h>
+#include <hurd/core.h>
+#include <limits.h>
+
+int
+main (int argc, char **argv)
+{
+ file_t coreserv;
+ int i;
+
+ if (argc < 2)
+ {
+ usage:
+ fprintf (stderr, "Usage: %s PID ...\n", program_invocation_short_name);
+ exit (1);
+ }
+
+ coreserv = path_lookup (_SERVERS_CORE, 0, 0);
+ if (coreserv == MACH_PORT_NULL)
+ {
+ perror (_SERVERS_CORE);
+ exit (1);
+ }
+
+ for (i = 1; i < argc; ++i)
+ {
+ char *end;
+ pid_t pid;
+ task_t task;
+
+ pid = strtol (&argv[i], &end, 10);
+ if (end == &argv[i] || *end != '\0')
+ goto usage;
+
+ task = pid2task ((pid_t) pid);
+ if (task == MACH_PORT_NULL)
+ fprintf (stderr, "pid2task: %d: %s\n", pid, strerror (errno));
+ else
+ {
+ char name[PATH_MAX];
+ file_t file;
+ sprintf (name, "core.%d", pid);
+ file = path_lookup (name, FS_LOOKUP_WRITE|FS_LOOKUP_CREATE,
+ 0666 &~ getumask ());
+ if (file == MACH_PORT_NULL)
+ perror (name);
+ else
+ {
+ error_t err = core_dump_task (coreserv, task,
+ file,
+ 0, 0,
+ getenv ("GNUTARGET"));
+ mach_port_deallocate (mach_task_self (), file);
+ if (err)
+ {
+ (void) remove (name);
+ fprintf (stderr, "core_dump_task: %d: %s\n",
+ pid, strerror (err));
+ }
+ }
+ }
+ mach_port_deallocate (mach_task_self (), task);
+ }
+
+ exit (0);
+}
diff --git a/hurd/=pending-changes b/hurd/=pending-changes
new file mode 100644
index 00000000..33660b46
--- /dev/null
+++ b/hurd/=pending-changes
@@ -0,0 +1,26 @@
+User visible:
+
+Change fsys_set_options interface to allow returning data & err+data.
+ fsys: fsys_t; options: data_t; do_children: int; err: error_t; result: data_t
+Add error_t to hurd_types.defs.
+
+Add notification calls to process.defs (and create process_notify.defs).
+(not yet)
+
+Add file_exchange_contents (not yet)
+
+Change file_getfh and fsys_getfile to use more convenient interface.
+
+Remove hostid/hostname calls from process.defs.
+
+Add serverport arg to auth_user_authenticate; change auth to use it to
+abort auth_user_authenticate when it's dead.
+
+Add io_revoke.
+
+
+Not user visible:
+
+Format of /var/login should be user:1 not user-1.
+ [Or as subdirectories, if a server supplies directory ops anyway]
+
diff --git a/libfshelp/trans.h b/libfshelp/trans.h
new file mode 100644
index 00000000..b2416453
--- /dev/null
+++ b/libfshelp/trans.h
@@ -0,0 +1,32 @@
+/*
+ Copyright (C) 1994 Free Software Foundation
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <mach.h>
+#include <hurd.h>
+#include <cthreads.h>
+#include <hurd/ports.h>
+#include "fshelp.h"
+
+struct transboot
+{
+ struct port_info pi;
+ file_t node;
+ struct trans_link *link;
+};
+
+spin_lock_t _fshelp_translistlock;
+struct trans_link *_fshelp_translist;
diff --git a/libnetfs/execserver.h b/libnetfs/execserver.h
new file mode 100644
index 00000000..6c432386
--- /dev/null
+++ b/libnetfs/execserver.h
@@ -0,0 +1,23 @@
+/*
+ Copyright (C) 1996 Free Software Foundation, Inc.
+ Written by Michael I. Bushnell, p/BSG.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+
+/* To contact the execserver */
+file_t _netfs_exec;
diff --git a/libnetfs/file-exec.c b/libnetfs/file-exec.c
new file mode 100644
index 00000000..af882028
--- /dev/null
+++ b/libnetfs/file-exec.c
@@ -0,0 +1,164 @@
+/*
+ Copyright (C) 1996 Free Software Foundation, Inc.
+ Written by Michael I. Bushnell, p/BSG.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+/* Written by Michael I. Bushnell, p/BSG. */
+
+#include "netfs.h"
+#include "execserver.h"
+#include "fs_S.h"
+#include <sys/stat.h>
+#include <fcntlbits.h>
+#include <hurd/exec.h>
+#include <hurd/paths.h>
+#include <string.h>
+#include <idvec.h>
+
+kern_return_t
+netfs_S_file_exec (struct protid *cred,
+ task_t task,
+ int flags,
+ char *argv,
+ u_int argvlen,
+ char *envp,
+ u_int envplen,
+ mach_port_t *fds,
+ u_int fdslen,
+ mach_port_t *portarray,
+ u_int portarraylen,
+ int *intarray,
+ u_int intarraylen,
+ mach_port_t *deallocnames,
+ u_int deallocnameslen,
+ mach_port_t *destroynames,
+ u_int destroynameslen)
+{
+ struct node *np;
+ error_t err;
+ struct protid *newpi;
+ int suid, sgid;
+
+ if (!cred)
+ return EOPNOTSUPP;
+
+ if (_netfs_exec == MACH_PORT_NULL)
+ _netfs_exec = file_name_lookup (_SERVERS_EXEC, 0, 0);
+ if (_netfs_exec == MACH_PORT_NULL)
+ return EOPNOTSUPP;
+
+ np = cred->po->np;
+
+ mutex_lock (&np->lock);
+
+ if ((cred->po->openstat & O_EXEC) == 0)
+ {
+ mutex_unlock (&np->lock);
+ return EBADF;
+ }
+
+ err = netfs_validate_stat (np, cred->credential);
+ if (err)
+ {
+ mutex_unlock (&np->lock);
+ return err;
+ }
+
+ if (!((np->nn_stat.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH))
+ || ((np->nn_stat.st_mode & S_IUSEUNK)
+ && (np->nn_stat.st_mode & (S_IEXEC << S_IUNKSHIFT)))))
+ {
+ mutex_unlock (&np->lock);
+ return EACCES;
+ }
+
+ if ((np->nn_stat.st_mode & S_IFMT) == S_IFDIR)
+ {
+ mutex_unlock (&np->lock);
+ return EACCES;
+ }
+
+ suid = np->nn_stat.st_mode & S_ISUID;
+ sgid = np->nn_stat.st_mode & S_ISGID;
+ if (suid || sgid)
+ {
+ int secure = 0;
+ error_t get_file_ids (struct idvec *uidsvec, struct idvec *gidsvec)
+ {
+ error_t err;
+ uid_t *uids, *gids;
+ int nuids, ngids;
+
+ netfs_interpret_credential (cred->credential, &uids, &nuids,
+ &gids, &ngids);
+
+ err = idvec_merge_ids (uidsvec, uids, nuids);
+ if (! err)
+ err = idvec_merge_ids (gidsvec, gids, ngids);
+ free (uids);
+ free (gids);
+ return err;
+ }
+ fshelp_exec_reauth (suid, np->nn_stat.st_uid, sgid, np->nn_stat.st_gid,
+ netfs_auth_server_port, get_file_ids,
+ portarray, portarraylen, fds, fdslen, &secure);
+ if (secure)
+ flags |= EXEC_SECURE | EXEC_NEWTASK;
+ }
+
+ /* If the user can't read the file, then we should use a new task,
+ which would be inaccessible to the user. Actually, this doesn't
+ work, because the proc server will still give out the task port
+ to the user. Too many things depend on that that it can't be
+ changed. So this vague attempt isn't even worth trying. */
+#if 0
+ if (diskfs_access (np, S_IREAD, cred))
+ flags |= EXEC_NEWTASK;
+#endif
+
+ newpi = netfs_make_protid (netfs_make_peropen (np, O_READ,
+ cred->po->dotdotport),
+ netfs_copy_credential (cred->credential));
+ mutex_unlock (&np->lock);
+
+ if (! err)
+ {
+ err = exec_exec (_netfs_exec,
+ ports_get_right (newpi),
+ MACH_MSG_TYPE_MAKE_SEND,
+ task, flags, argv, argvlen, envp, envplen,
+ fds, MACH_MSG_TYPE_COPY_SEND, fdslen,
+ portarray, MACH_MSG_TYPE_COPY_SEND, portarraylen,
+ intarray, intarraylen, deallocnames, deallocnameslen,
+ destroynames, destroynameslen);
+ ports_port_deref (newpi);
+ }
+
+ if (! err)
+ {
+ unsigned int i;
+
+ mach_port_deallocate (mach_task_self (), task);
+ for (i = 0; i < fdslen; i++)
+ mach_port_deallocate (mach_task_self (), fds[i]);
+ for (i = 0; i < portarraylen; i++)
+ mach_port_deallocate (mach_task_self (), portarray[i]);
+ }
+
+ return err;
+}
diff --git a/libports/default-uninhibitable-rpcs.c b/libports/default-uninhibitable-rpcs.c
new file mode 100644
index 00000000..60aeccab
--- /dev/null
+++ b/libports/default-uninhibitable-rpcs.c
@@ -0,0 +1,27 @@
+/* Default definition of default_uninhibitable_rpcs
+
+ Copyright (C) 1996 Free Software Foundation, Inc.
+
+ Written by Miles Bader <miles@gnu.ai.mit.edu>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "ports.h"
+
+static struct ports_msg_id_range
+interrupt_operation_ids = { 33000, 33001, 0 };
+
+struct ports_msg_id_range *
+ports_default_uninhibitable_rpcs = &interrupt_operation_ids;
diff --git a/libports/import-port.c b/libports/import-port.c
new file mode 100644
index 00000000..b958245f
--- /dev/null
+++ b/libports/import-port.c
@@ -0,0 +1,116 @@
+/* Create a new port structure using an externally supplied receive right
+
+ Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+
+ Written by Michael I. Bushnell.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "ports.h"
+#include <assert.h>
+#include <cthreads.h>
+#include <hurd/ihash.h>
+#include <mach/notify.h>
+
+/* For an existing receive right PORT, create and return in RESULT a new port
+ structure; BUCKET, SIZE, and CLASS args are as for ports_create_port. */
+error_t
+ports_import_port (struct port_class *class, struct port_bucket *bucket,
+ mach_port_t port, size_t size, void *result)
+{
+ error_t err;
+ mach_port_status_t stat;
+ struct port_info *pi;
+ mach_port_t foo;
+
+ err = mach_port_get_receive_status (mach_task_self (), port, &stat);
+ if (err)
+ return err;
+
+ if (size < sizeof (struct port_info))
+ size = sizeof (struct port_info);
+
+ pi = malloc (size);
+ if (! pi)
+ return ENOMEM;
+
+ pi->class = class;
+ pi->refcnt = 1 + !!stat.mps_srights;
+ pi->weakrefcnt = 0;
+ pi->cancel_threshold = 0;
+ pi->mscount = stat.mps_mscount;
+ pi->flags = stat.mps_srights ? PORT_HAS_SENDRIGHTS : 0;
+ pi->port_right = port;
+ pi->current_rpcs = 0;
+ pi->bucket = bucket;
+
+ mutex_lock (&_ports_lock);
+
+ loop:
+ if (class->flags & PORT_CLASS_NO_ALLOC)
+ {
+ class->flags |= PORT_CLASS_ALLOC_WAIT;
+ if (hurd_condition_wait (&_ports_block, &_ports_lock))
+ goto cancelled;
+ goto loop;
+ }
+ if (bucket->flags & PORT_BUCKET_NO_ALLOC)
+ {
+ bucket->flags |= PORT_BUCKET_ALLOC_WAIT;
+ if (hurd_condition_wait (&_ports_block, &_ports_lock))
+ goto cancelled;
+ goto loop;
+ }
+
+ err = ihash_add (bucket->htable, port, pi, &pi->hentry);
+ if (err)
+ goto lose;
+
+ pi->next = class->ports;
+ pi->prevp = &class->ports;
+ if (class->ports)
+ class->ports->prevp = &pi->next;
+ class->ports = pi;
+ bucket->count++;
+ class->count++;
+ mutex_unlock (&_ports_lock);
+
+ mach_port_move_member (mach_task_self (), port, bucket->portset);
+
+ if (stat.mps_srights)
+ {
+ err = mach_port_request_notification (mach_task_self (), port,
+ MACH_NOTIFY_NO_SENDERS,
+ stat.mps_mscount,
+ port, MACH_MSG_TYPE_MAKE_SEND_ONCE,
+ &foo);
+ assert_perror (err);
+ if (foo != MACH_PORT_NULL)
+ mach_port_deallocate (mach_task_self (), foo);
+ }
+
+ *(void **)result = pi;
+ return 0;
+
+ cancelled:
+ err = EINTR;
+ lose:
+ mutex_unlock (&_ports_lock);
+ free (pi);
+
+ return err;
+}
diff --git a/libps/ps_msg.h b/libps/ps_msg.h
new file mode 100644
index 00000000..21252a22
--- /dev/null
+++ b/libps/ps_msg.h
@@ -0,0 +1,633 @@
+#ifndef _ps_msg_user_
+#define _ps_msg_user_
+
+/* Module msg */
+
+#include <mach/kern_return.h>
+#include <mach/port.h>
+#include <mach/message.h>
+
+#include <mach/std_types.h>
+#include <mach/mach_types.h>
+#include <device/device_types.h>
+#include <device/net_status.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/resource.h>
+#include <sys/utsname.h>
+#include <hurd/hurd_types.h>
+
+/* Routine msg_sig_post */
+#ifdef mig_external
+mig_external
+#else
+extern
+#endif
+kern_return_t ps_msg_sig_post
+#if defined(LINTLIBRARY)
+ (process, signal, refport)
+ mach_port_t process;
+ int signal;
+ mach_port_t refport;
+{ return ps_msg_sig_post(process, signal, refport); }
+#else
+(
+ mach_port_t process,
+ int signal,
+ mach_port_t refport
+);
+#endif
+
+/* Routine msg_proc_newids */
+#ifdef mig_external
+mig_external
+#else
+extern
+#endif
+kern_return_t ps_msg_proc_newids
+#if defined(LINTLIBRARY)
+ (process, task, ppid, pgrp, orphaned)
+ mach_port_t process;
+ mach_port_t task;
+ pid_t ppid;
+ pid_t pgrp;
+ int orphaned;
+{ return ps_msg_proc_newids(process, task, ppid, pgrp, orphaned); }
+#else
+(
+ mach_port_t process,
+ mach_port_t task,
+ pid_t ppid,
+ pid_t pgrp,
+ int orphaned
+);
+#endif
+
+/* Routine msg_add_auth */
+#ifdef mig_external
+mig_external
+#else
+extern
+#endif
+kern_return_t ps_msg_add_auth
+#if defined(LINTLIBRARY)
+ (process, auth)
+ mach_port_t process;
+ auth_t auth;
+{ return ps_msg_add_auth(process, auth); }
+#else
+(
+ mach_port_t process,
+ auth_t auth
+);
+#endif
+
+/* Routine msg_del_auth */
+#ifdef mig_external
+mig_external
+#else
+extern
+#endif
+kern_return_t ps_msg_del_auth
+#if defined(LINTLIBRARY)
+ (process, task, uids, uidsCnt, gids, gidsCnt)
+ mach_port_t process;
+ mach_port_t task;
+ intarray_t uids;
+ mach_msg_type_number_t uidsCnt;
+ intarray_t gids;
+ mach_msg_type_number_t gidsCnt;
+{ return ps_msg_del_auth(process, task, uids, uidsCnt, gids, gidsCnt); }
+#else
+(
+ mach_port_t process,
+ mach_port_t task,
+ intarray_t uids,
+ mach_msg_type_number_t uidsCnt,
+ intarray_t gids,
+ mach_msg_type_number_t gidsCnt
+);
+#endif
+
+/* Routine msg_get_init_port */
+#ifdef mig_external
+mig_external
+#else
+extern
+#endif
+kern_return_t ps_msg_get_init_port
+#if defined(LINTLIBRARY)
+ (process, refport, which, port)
+ mach_port_t process;
+ mach_port_t refport;
+ int which;
+ mach_port_t *port;
+{ return ps_msg_get_init_port(process, refport, which, port); }
+#else
+(
+ mach_port_t process,
+ mach_port_t refport,
+ int which,
+ mach_port_t *port
+);
+#endif
+
+/* Routine msg_set_init_port */
+#ifdef mig_external
+mig_external
+#else
+extern
+#endif
+kern_return_t ps_msg_set_init_port
+#if defined(LINTLIBRARY)
+ (process, refport, which, port, portPoly)
+ mach_port_t process;
+ mach_port_t refport;
+ int which;
+ mach_port_t port;
+ mach_msg_type_name_t portPoly;
+{ return ps_msg_set_init_port(process, refport, which, port, portPoly); }
+#else
+(
+ mach_port_t process,
+ mach_port_t refport,
+ int which,
+ mach_port_t port,
+ mach_msg_type_name_t portPoly
+);
+#endif
+
+/* Routine msg_get_init_ports */
+#ifdef mig_external
+mig_external
+#else
+extern
+#endif
+kern_return_t ps_msg_get_init_ports
+#if defined(LINTLIBRARY)
+ (process, refport, ports, portsCnt)
+ mach_port_t process;
+ mach_port_t refport;
+ portarray_t *ports;
+ mach_msg_type_number_t *portsCnt;
+{ return ps_msg_get_init_ports(process, refport, ports, portsCnt); }
+#else
+(
+ mach_port_t process,
+ mach_port_t refport,
+ portarray_t *ports,
+ mach_msg_type_number_t *portsCnt
+);
+#endif
+
+/* Routine msg_set_init_ports */
+#ifdef mig_external
+mig_external
+#else
+extern
+#endif
+kern_return_t ps_msg_set_init_ports
+#if defined(LINTLIBRARY)
+ (process, refport, ports, portsPoly, portsCnt)
+ mach_port_t process;
+ mach_port_t refport;
+ portarray_t ports;
+ mach_msg_type_name_t portsPoly;
+ mach_msg_type_number_t portsCnt;
+{ return ps_msg_set_init_ports(process, refport, ports, portsPoly, portsCnt); }
+#else
+(
+ mach_port_t process,
+ mach_port_t refport,
+ portarray_t ports,
+ mach_msg_type_name_t portsPoly,
+ mach_msg_type_number_t portsCnt
+);
+#endif
+
+/* Routine msg_get_init_int */
+#ifdef mig_external
+mig_external
+#else
+extern
+#endif
+kern_return_t ps_msg_get_init_int
+#if defined(LINTLIBRARY)
+ (process, refport, which, value)
+ mach_port_t process;
+ mach_port_t refport;
+ int which;
+ int *value;
+{ return ps_msg_get_init_int(process, refport, which, value); }
+#else
+(
+ mach_port_t process,
+ mach_port_t refport,
+ int which,
+ int *value
+);
+#endif
+
+/* Routine msg_set_init_int */
+#ifdef mig_external
+mig_external
+#else
+extern
+#endif
+kern_return_t ps_msg_set_init_int
+#if defined(LINTLIBRARY)
+ (process, refport, which, value)
+ mach_port_t process;
+ mach_port_t refport;
+ int which;
+ int value;
+{ return ps_msg_set_init_int(process, refport, which, value); }
+#else
+(
+ mach_port_t process,
+ mach_port_t refport,
+ int which,
+ int value
+);
+#endif
+
+/* Routine msg_get_init_ints */
+#ifdef mig_external
+mig_external
+#else
+extern
+#endif
+kern_return_t ps_msg_get_init_ints
+#if defined(LINTLIBRARY)
+ (process, refport, values, valuesCnt)
+ mach_port_t process;
+ mach_port_t refport;
+ intarray_t *values;
+ mach_msg_type_number_t *valuesCnt;
+{ return ps_msg_get_init_ints(process, refport, values, valuesCnt); }
+#else
+(
+ mach_port_t process,
+ mach_port_t refport,
+ intarray_t *values,
+ mach_msg_type_number_t *valuesCnt
+);
+#endif
+
+/* Routine msg_set_init_ints */
+#ifdef mig_external
+mig_external
+#else
+extern
+#endif
+kern_return_t ps_msg_set_init_ints
+#if defined(LINTLIBRARY)
+ (process, refport, values, valuesCnt)
+ mach_port_t process;
+ mach_port_t refport;
+ intarray_t values;
+ mach_msg_type_number_t valuesCnt;
+{ return ps_msg_set_init_ints(process, refport, values, valuesCnt); }
+#else
+(
+ mach_port_t process,
+ mach_port_t refport,
+ intarray_t values,
+ mach_msg_type_number_t valuesCnt
+);
+#endif
+
+/* Routine msg_get_dtable */
+#ifdef mig_external
+mig_external
+#else
+extern
+#endif
+kern_return_t ps_msg_get_dtable
+#if defined(LINTLIBRARY)
+ (process, refport, dtable, dtableCnt)
+ mach_port_t process;
+ mach_port_t refport;
+ portarray_t *dtable;
+ mach_msg_type_number_t *dtableCnt;
+{ return ps_msg_get_dtable(process, refport, dtable, dtableCnt); }
+#else
+(
+ mach_port_t process,
+ mach_port_t refport,
+ portarray_t *dtable,
+ mach_msg_type_number_t *dtableCnt
+);
+#endif
+
+/* Routine msg_set_dtable */
+#ifdef mig_external
+mig_external
+#else
+extern
+#endif
+kern_return_t ps_msg_set_dtable
+#if defined(LINTLIBRARY)
+ (process, refport, dtable, dtablePoly, dtableCnt)
+ mach_port_t process;
+ mach_port_t refport;
+ portarray_t dtable;
+ mach_msg_type_name_t dtablePoly;
+ mach_msg_type_number_t dtableCnt;
+{ return ps_msg_set_dtable(process, refport, dtable, dtablePoly, dtableCnt); }
+#else
+(
+ mach_port_t process,
+ mach_port_t refport,
+ portarray_t dtable,
+ mach_msg_type_name_t dtablePoly,
+ mach_msg_type_number_t dtableCnt
+);
+#endif
+
+/* Routine msg_get_fd */
+#ifdef mig_external
+mig_external
+#else
+extern
+#endif
+kern_return_t ps_msg_get_fd
+#if defined(LINTLIBRARY)
+ (process, refport, fd, port)
+ mach_port_t process;
+ mach_port_t refport;
+ int fd;
+ mach_port_t *port;
+{ return ps_msg_get_fd(process, refport, fd, port); }
+#else
+(
+ mach_port_t process,
+ mach_port_t refport,
+ int fd,
+ mach_port_t *port
+);
+#endif
+
+/* Routine msg_set_fd */
+#ifdef mig_external
+mig_external
+#else
+extern
+#endif
+kern_return_t ps_msg_set_fd
+#if defined(LINTLIBRARY)
+ (process, refport, fd, port, portPoly)
+ mach_port_t process;
+ mach_port_t refport;
+ int fd;
+ mach_port_t port;
+ mach_msg_type_name_t portPoly;
+{ return ps_msg_set_fd(process, refport, fd, port, portPoly); }
+#else
+(
+ mach_port_t process,
+ mach_port_t refport,
+ int fd,
+ mach_port_t port,
+ mach_msg_type_name_t portPoly
+);
+#endif
+
+/* Routine msg_get_environment */
+#ifdef mig_external
+mig_external
+#else
+extern
+#endif
+kern_return_t ps_msg_get_environment
+#if defined(LINTLIBRARY)
+ (process, value, valueCnt)
+ mach_port_t process;
+ data_t *value;
+ mach_msg_type_number_t *valueCnt;
+{ return ps_msg_get_environment(process, value, valueCnt); }
+#else
+(
+ mach_port_t process,
+ data_t *value,
+ mach_msg_type_number_t *valueCnt
+);
+#endif
+
+/* Routine msg_set_environment */
+#ifdef mig_external
+mig_external
+#else
+extern
+#endif
+kern_return_t ps_msg_set_environment
+#if defined(LINTLIBRARY)
+ (process, refport, value, valueCnt)
+ mach_port_t process;
+ mach_port_t refport;
+ data_t value;
+ mach_msg_type_number_t valueCnt;
+{ return ps_msg_set_environment(process, refport, value, valueCnt); }
+#else
+(
+ mach_port_t process,
+ mach_port_t refport,
+ data_t value,
+ mach_msg_type_number_t valueCnt
+);
+#endif
+
+/* Routine msg_get_env_variable */
+#ifdef mig_external
+mig_external
+#else
+extern
+#endif
+kern_return_t ps_msg_get_env_variable
+#if defined(LINTLIBRARY)
+ (process, variable, value, valueCnt)
+ mach_port_t process;
+ string_t variable;
+ data_t *value;
+ mach_msg_type_number_t *valueCnt;
+{ return ps_msg_get_env_variable(process, variable, value, valueCnt); }
+#else
+(
+ mach_port_t process,
+ string_t variable,
+ data_t *value,
+ mach_msg_type_number_t *valueCnt
+);
+#endif
+
+/* Routine msg_set_env_variable */
+#ifdef mig_external
+mig_external
+#else
+extern
+#endif
+kern_return_t ps_msg_set_env_variable
+#if defined(LINTLIBRARY)
+ (process, refport, variable, value, replace)
+ mach_port_t process;
+ mach_port_t refport;
+ string_t variable;
+ string_t value;
+ boolean_t replace;
+{ return ps_msg_set_env_variable(process, refport, variable, value, replace); }
+#else
+(
+ mach_port_t process,
+ mach_port_t refport,
+ string_t variable,
+ string_t value,
+ boolean_t replace
+);
+#endif
+
+/* Routine msg_startup_dosync */
+#ifdef mig_external
+mig_external
+#else
+extern
+#endif
+kern_return_t ps_msg_startup_dosync
+#if defined(LINTLIBRARY)
+ (process)
+ mach_port_t process;
+{ return ps_msg_startup_dosync(process); }
+#else
+(
+ mach_port_t process
+);
+#endif
+
+/* Routine msg_sig_post_untraced */
+#ifdef mig_external
+mig_external
+#else
+extern
+#endif
+kern_return_t ps_msg_sig_post_untraced
+#if defined(LINTLIBRARY)
+ (process, signal, refport)
+ mach_port_t process;
+ int signal;
+ mach_port_t refport;
+{ return ps_msg_sig_post_untraced(process, signal, refport); }
+#else
+(
+ mach_port_t process,
+ int signal,
+ mach_port_t refport
+);
+#endif
+
+/* Routine msg_get_exec_flags */
+#ifdef mig_external
+mig_external
+#else
+extern
+#endif
+kern_return_t ps_msg_get_exec_flags
+#if defined(LINTLIBRARY)
+ (process, refport, flags)
+ mach_port_t process;
+ mach_port_t refport;
+ int *flags;
+{ return ps_msg_get_exec_flags(process, refport, flags); }
+#else
+(
+ mach_port_t process,
+ mach_port_t refport,
+ int *flags
+);
+#endif
+
+/* Routine msg_set_all_exec_flags */
+#ifdef mig_external
+mig_external
+#else
+extern
+#endif
+kern_return_t ps_msg_set_all_exec_flags
+#if defined(LINTLIBRARY)
+ (process, refport, flags)
+ mach_port_t process;
+ mach_port_t refport;
+ int flags;
+{ return ps_msg_set_all_exec_flags(process, refport, flags); }
+#else
+(
+ mach_port_t process,
+ mach_port_t refport,
+ int flags
+);
+#endif
+
+/* Routine msg_set_some_exec_flags */
+#ifdef mig_external
+mig_external
+#else
+extern
+#endif
+kern_return_t ps_msg_set_some_exec_flags
+#if defined(LINTLIBRARY)
+ (process, refport, flags)
+ mach_port_t process;
+ mach_port_t refport;
+ int flags;
+{ return ps_msg_set_some_exec_flags(process, refport, flags); }
+#else
+(
+ mach_port_t process,
+ mach_port_t refport,
+ int flags
+);
+#endif
+
+/* Routine msg_clear_some_exec_flags */
+#ifdef mig_external
+mig_external
+#else
+extern
+#endif
+kern_return_t ps_msg_clear_some_exec_flags
+#if defined(LINTLIBRARY)
+ (process, refport, flags)
+ mach_port_t process;
+ mach_port_t refport;
+ int flags;
+{ return ps_msg_clear_some_exec_flags(process, refport, flags); }
+#else
+(
+ mach_port_t process,
+ mach_port_t refport,
+ int flags
+);
+#endif
+
+/* Routine msg_report_wait */
+#ifdef mig_external
+mig_external
+#else
+extern
+#endif
+kern_return_t ps_msg_report_wait
+#if defined(LINTLIBRARY)
+ (process, thread, wait_desc, wait_rpc)
+ mach_port_t process;
+ mach_port_t thread;
+ string_t wait_desc;
+ int *wait_rpc;
+{ return ps_msg_report_wait(process, thread, wait_desc, wait_rpc); }
+#else
+(
+ mach_port_t process,
+ mach_port_t thread,
+ string_t wait_desc,
+ int *wait_rpc
+);
+#endif
+
+#endif /* not defined(_ps_msg_user_) */
diff --git a/libps/ps_term.h b/libps/ps_term.h
new file mode 100644
index 00000000..259658c5
--- /dev/null
+++ b/libps/ps_term.h
@@ -0,0 +1,216 @@
+#ifndef _ps_term_user_
+#define _ps_term_user_
+
+/* Module term */
+
+#include <mach/kern_return.h>
+#include <mach/port.h>
+#include <mach/message.h>
+
+#include <mach/std_types.h>
+#include <mach/mach_types.h>
+#include <device/device_types.h>
+#include <device/net_status.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/resource.h>
+#include <sys/utsname.h>
+#include <hurd/hurd_types.h>
+
+/* Routine term_getctty */
+#ifdef mig_external
+mig_external
+#else
+extern
+#endif
+kern_return_t ps_term_getctty
+#if defined(LINTLIBRARY)
+ (terminal, ctty)
+ io_t terminal;
+ mach_port_t *ctty;
+{ return ps_term_getctty(terminal, ctty); }
+#else
+(
+ io_t terminal,
+ mach_port_t *ctty
+);
+#endif
+
+/* Routine term_open_ctty */
+#ifdef mig_external
+mig_external
+#else
+extern
+#endif
+kern_return_t ps_term_open_ctty
+#if defined(LINTLIBRARY)
+ (terminal, pid, pgrp, newtty)
+ io_t terminal;
+ pid_t pid;
+ pid_t pgrp;
+ mach_port_t *newtty;
+{ return ps_term_open_ctty(terminal, pid, pgrp, newtty); }
+#else
+(
+ io_t terminal,
+ pid_t pid,
+ pid_t pgrp,
+ mach_port_t *newtty
+);
+#endif
+
+/* Routine term_set_nodename */
+#ifdef mig_external
+mig_external
+#else
+extern
+#endif
+kern_return_t ps_term_set_nodename
+#if defined(LINTLIBRARY)
+ (terminal, name)
+ io_t terminal;
+ string_t name;
+{ return ps_term_set_nodename(terminal, name); }
+#else
+(
+ io_t terminal,
+ string_t name
+);
+#endif
+
+/* Routine term_get_nodename */
+#ifdef mig_external
+mig_external
+#else
+extern
+#endif
+kern_return_t ps_term_get_nodename
+#if defined(LINTLIBRARY)
+ (terminal, name)
+ io_t terminal;
+ string_t name;
+{ return ps_term_get_nodename(terminal, name); }
+#else
+(
+ io_t terminal,
+ string_t name
+);
+#endif
+
+/* Routine term_set_filenode */
+#ifdef mig_external
+mig_external
+#else
+extern
+#endif
+kern_return_t ps_term_set_filenode
+#if defined(LINTLIBRARY)
+ (terminal, filenode)
+ io_t terminal;
+ file_t filenode;
+{ return ps_term_set_filenode(terminal, filenode); }
+#else
+(
+ io_t terminal,
+ file_t filenode
+);
+#endif
+
+/* Routine term_get_bottom_type */
+#ifdef mig_external
+mig_external
+#else
+extern
+#endif
+kern_return_t ps_term_get_bottom_type
+#if defined(LINTLIBRARY)
+ (terminal, ttype)
+ io_t terminal;
+ int *ttype;
+{ return ps_term_get_bottom_type(terminal, ttype); }
+#else
+(
+ io_t terminal,
+ int *ttype
+);
+#endif
+
+/* Routine term_on_machdev */
+#ifdef mig_external
+mig_external
+#else
+extern
+#endif
+kern_return_t ps_term_on_machdev
+#if defined(LINTLIBRARY)
+ (terminal, machdev)
+ io_t terminal;
+ mach_port_t machdev;
+{ return ps_term_on_machdev(terminal, machdev); }
+#else
+(
+ io_t terminal,
+ mach_port_t machdev
+);
+#endif
+
+/* Routine term_on_hurddev */
+#ifdef mig_external
+mig_external
+#else
+extern
+#endif
+kern_return_t ps_term_on_hurddev
+#if defined(LINTLIBRARY)
+ (terminal, hurddev)
+ io_t terminal;
+ io_t hurddev;
+{ return ps_term_on_hurddev(terminal, hurddev); }
+#else
+(
+ io_t terminal,
+ io_t hurddev
+);
+#endif
+
+/* Routine term_on_pty */
+#ifdef mig_external
+mig_external
+#else
+extern
+#endif
+kern_return_t ps_term_on_pty
+#if defined(LINTLIBRARY)
+ (terminal, ptymaster)
+ io_t terminal;
+ io_t *ptymaster;
+{ return ps_term_on_pty(terminal, ptymaster); }
+#else
+(
+ io_t terminal,
+ io_t *ptymaster
+);
+#endif
+
+/* Routine termctty_open_terminal */
+#ifdef mig_external
+mig_external
+#else
+extern
+#endif
+kern_return_t ps_termctty_open_terminal
+#if defined(LINTLIBRARY)
+ (ctty, flags, terminal)
+ mach_port_t ctty;
+ int flags;
+ mach_port_t *terminal;
+{ return ps_termctty_open_terminal(ctty, flags, terminal); }
+#else
+(
+ mach_port_t ctty,
+ int flags,
+ mach_port_t *terminal
+);
+#endif
+
+#endif /* not defined(_ps_term_user_) */
diff --git a/libtreefs/Makefile b/libtreefs/Makefile
new file mode 100644
index 00000000..89d95e9b
--- /dev/null
+++ b/libtreefs/Makefile
@@ -0,0 +1,40 @@
+# Makefile for libtreefs
+#
+# Copyright (C) 1995 Free Software Foundation, Inc.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2, or (at
+# your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+dir := libtreefs
+makemode := library
+
+libname = libtreefs
+installhdrs = treefs.h
+# RPC stubs
+S_SRCS = s-file.c s-dir.c s-io.c s-fsys.c
+OTHERSRCS = defhooks.c dir-hooks.c dir-lookup.c fsys-getroot.c fsys-hooks.c \
+ fsys-startup.c hooks.c mdir.c nlist.c node-hooks.c rights.c \
+ trans-help.c trans-start.c
+SRCS = $(OTHERSRCS) $(S_SRCS)
+LCLHDRS = treefs.h fs-mutate.h
+
+MIGSTUBS = fsServer.o ioServer.o fsysServer.o
+OBJS = $(sort $(subst .c,.o,$(SRCS)) $(MIGSTUBS)
+
+MIGSFLAGS = -imacros fs-mutate.h
+MIGCOMSFLAGS = -prefix treefs_
+notify-MIGSFLAGS = -DSEQNOS
+
+include ../Makeconf
+
diff --git a/libtreefs/defhooks.c b/libtreefs/defhooks.c
new file mode 100644
index 00000000..bed0b550
--- /dev/null
+++ b/libtreefs/defhooks.c
@@ -0,0 +1,80 @@
+/* Default functions for the hook vector
+
+ Copyright (C) 1995 Free Software Foundation, Inc.
+
+ Written by Miles Bader <miles@gnu.ai.mit.edu>
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "treefs.h"
+#include "treefs-s-hooks.h"
+
+typedef void (*vf)();
+
+static error_t unsupp () { return EOPNOTSUPP; }
+static error_t nop () { return 0; }
+static int true () { return 1; }
+
+/* Most hooks return an error_t, so the default for anything not mentioned in
+ this array is to return EOPNOTSUPP. Any hooks returning different types,
+ or with some different default behavior should be mentioned here. */
+treefs_hook_vector_init_t treefs_default_hooks =
+{
+ /* directory rpcs */
+ [TREEFS_HOOK_S_DIR_LOOKUP] = (vf)_treefs_s_dir_lookup,
+
+ [TREEFS_HOOK_S_FSYS_GETROOT] = (vf)_treefs_s_fsys_getroot,
+ [TREEFS_HOOK_S_FSYS_SYNCFS] = (vf)nop,
+
+ /* Non-rpc fsys hooks */
+ [TREEFS_HOOK_FSYS_CREATE_NODE] = (vf)_treefs_fsys_create_node,
+ [TREEFS_HOOK_FSYS_DESTROY_NODE] = (vf)_treefs_fsys_destroy_node,
+ [TREEFS_HOOK_FSYS_GET_ROOT] = (vf)_treefs_fsys_get_root,
+
+ /* Node hooks */
+ [TREEFS_HOOK_NODE_TYPE] = (vf)_treefs_node_type,
+ [TREEFS_HOOK_NODE_UNLINKED] = (vf)true,
+ [TREEFS_HOOK_NODE_MOD_LINK_COUNT] = (vf)_treefs_node_mod_link_count,
+ [TREEFS_HOOK_DIR_LOOKUP] = (vf)_treefs_dir_lookup,
+ [TREEFS_HOOK_DIR_NOENT] = (vf)_treefs_dir_noent,
+ [TREEFS_HOOK_DIR_CREATE_CHILD] = (vf)_treefs_dir_create_child,
+ [TREEFS_HOOK_DIR_LINK] = (vf)_treefs_dir_link,
+ [TREEFS_HOOK_DIR_UNLINK] = (vf)_treefs_dir_unlink,
+ [TREEFS_HOOK_NODE_OWNED] = (vf)_treefs_node_owned,
+ [TREEFS_HOOK_NODE_ACCESS] = (vf)_treefs_node_access,
+ [TREEFS_HOOK_NODE_START_TRANSLATOR] = (vf)_treefs_node_start_translator,
+ [TREEFS_HOOK_NODE_INIT] = (vf)nop,
+ [TREEFS_HOOK_DIR_INIT] = (vf)nop,
+ [TREEFS_HOOK_NODE_INIT_PEROPEN] = (vf)nop,
+ [TREEFS_HOOK_NODE_INIT_HANDLE] = (vf)nop,
+ [TREEFS_HOOK_NODE_FINALIZE] = (vf)nop,
+ [TREEFS_HOOK_NODE_FINALIZE_PEROPEN] = (vf)nop,
+ [TREEFS_HOOK_NODE_FINALIZE_HANDLE] = (vf)nop,
+
+ /* Reference counting support */
+ [TREEFS_HOOK_NODE_NEW_REFS] = (vf)nop,
+ [TREEFS_HOOK_NODE_LOST_REFS] = (vf)nop,
+ [TREEFS_HOOK_NODE_TRY_DROPPING_WEAK_REFS] = (vf)nop,
+};
+
+void _treefs_init_defhooks()
+{
+ int i;
+ for (i = 0; i < TREEFS_NUM_HOOKS; i++)
+ if (!treefs_default_hooks[i])
+ treefs_default_hooks[i] = (vf)unsupp;
+}
diff --git a/libtreefs/dir-hooks.c b/libtreefs/dir-hooks.c
new file mode 100644
index 00000000..5c54039a
--- /dev/null
+++ b/libtreefs/dir-hooks.c
@@ -0,0 +1,136 @@
+/* Default hooks for directory nodes
+
+ Copyright (C) 1995 Free Software Foundation, Inc.
+
+ Written by Miles Bader <miles@gnu.ai.mit.edu>
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <sys/fcntl.h>
+
+#include "treefs.h"
+
+/* ---------------------------------------------------------------- */
+
+/* Return in CHILD a new node with one reference, presumably a possible child
+ of DIR, with a mode MODE. All attempts to create a new node go through
+ this hook, so it may be overridden to easily control creation (e.g.,
+ replacing it with a hook that always returns EPERM). Note that this
+ routine doesn't actually enter the child into the directory, or give the
+ node a non-zero link count, that should be done by the caller. */
+error_t
+_treefs_dir_create_child (struct treefs_node *dir,
+ mode_t mode, struct treefs_auth *auth,
+ struct treefs_node **child)
+{
+ error_t err;
+
+ if (!treefs_node_isdir (dir))
+ return ENOTDIR;
+
+ err = treefs_fsys_create_node (dir->fsys, dir, mode, auth, child);
+ if (err)
+ return err;
+
+ return 0;
+}
+
+/* ---------------------------------------------------------------- */
+
+/* Lookup NAME in DIR, returning the result in CHILD; AUTH should be used to
+ do authentication. FLAGS is the open flags; if FLAGS contains O_CREAT,
+ and NAME is not found, then an entry should be created with a mode of
+ CREATE_MODE (which includes the S_IFMT bits, e.g., S_IFREG means a normal
+ file), unless O_EXCL is also set, in which case EEXIST should be returned.
+ Possible special errors returned include: EAGAIN -- result would be the
+ parent of our filesystem root. */
+error_t
+_treefs_dir_lookup (struct treefs_node *dir, char *name,
+ struct treefs_auth *auth,
+ int flags, int create_mode,
+ struct treefs_node **child)
+{
+ error_t err;
+
+ if (strcmp (name, "..") == 0 && dir == dir->fsys->root)
+ /* Whoops, the result is above our heads. */
+ err = EAGAIN;
+ else
+ /* See if we've got an in-core entry for this file. */
+ err = treefs_mdir_get (dir, name, child);
+
+ if (err == 0 && (flags & O_EXCL))
+ return EEXIST;
+
+ if (err == ENOENT)
+ /* See if there's some other way of getting this file. */
+ err = treefs_dir_noent (dir, name, auth, flags, create_mode, child);
+
+ if (err == ENOENT && (flags & O_CREAT))
+ /* No such file, but the user wants to create it. */
+ {
+ err = treefs_dir_create_child (dir, create_mode, auth, child);
+ if (!err)
+ {
+ err = treefs_dir_link (dir, name, *child, auth);
+ if (err)
+ treefs_node_unref (*child);
+ }
+ }
+
+ return err;
+}
+
+/* ---------------------------------------------------------------- */
+
+/* Link the node CHILD into DIR as NAME, using AUTH to check authentication.
+ DIR should be locked and CHILD shouldn't be. The default hook puts it
+ into DIR's in-core directory, and uses a reference to CHILD. */
+error_t
+_treefs_dir_link (struct treefs_node *dir, char *name,
+ struct treefs_node *child, struct treefs_auth *auth)
+{
+ struct treefs_node *old_child;
+ error_t err = treefs_node_mod_link_count (child, 1);
+ if (!err)
+ {
+ err = treefs_mdir_add (dir, name, child, &old_child);
+ if (err)
+ /* back out */
+ treefs_node_mod_link_count (child, -1);
+ else if (old_child)
+ treefs_node_mod_link_count (old_child, -1);
+ }
+ return err;
+}
+
+/* Remove the entry NAME from DIR, using AUTH to check authentication. DIR
+ should be locked. The default hook removes NAME from DIR's in-core
+ directory. */
+error_t
+_treefs_dir_unlink (struct treefs_node *dir, char *name,
+ struct treefs_auth *auth)
+{
+ struct treefs_node *old_child;
+ error_t err = treefs_mdir_remove (dir, name, &old_child);
+ if (!err && old_child)
+ {
+ treefs_node_mod_link_count (old_child, -1);
+ treefs_node_unref (old_child);
+ }
+ return err;
+}
diff --git a/libtreefs/dir-lookup.c b/libtreefs/dir-lookup.c
new file mode 100644
index 00000000..51c2cbd2
--- /dev/null
+++ b/libtreefs/dir-lookup.c
@@ -0,0 +1,305 @@
+/* Default treefs_s_dir_lookup hook
+
+ Copyright (C) 1992, 1993, 1994, 1995 Free Software Foundation, Inc.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <fcntl.h>
+#include <string.h>
+
+#include <hurd/fsys.h>
+
+#include "treefs.h"
+#include "treefs-s-hooks.h"
+
+/* Default dir_lookup hook. This code was originally copied from diskfs. */
+error_t
+_treefs_s_dir_lookup (struct treefs_handle *h,
+ char *path, int flags, mode_t mode,
+ enum retry_type *retry, char *retry_name,
+ file_t *result, mach_msg_type_name_t *result_type)
+{
+ struct treefs_node *dir;
+ struct treefs_node *node;
+ unsigned symlink_expansions = 0;
+ error_t err = 0;
+ char *path_buf = 0;
+ int path_buf_len = 0;
+ int lastcomp = 0;
+ int mustbedir = 0;
+
+ flags &= O_HURD;
+ mode &= ~S_IFMT;
+
+ /* Skip leading slashes */
+ while (path[0] == '/')
+ path++;
+
+ *result_type = MACH_MSG_TYPE_MAKE_SEND;
+ *retry = FS_RETRY_NORMAL;
+ retry_name[0] = '\0';
+
+ if (path[0] == '\0')
+ {
+ mustbedir = 1;
+
+ /* Set things up in the state expected by the code from gotit: on. */
+ dir = 0;
+ node = h->po->node;
+ mutex_lock (&node->lock);
+ treefs_node_ref (node);
+ goto gotit;
+ }
+
+ dir = h->po->node;
+ mutex_lock (&dir->lock);
+ node = 0;
+
+ treefs_node_ref (dir); /* acquire a ref for later node_release */
+
+ do
+ {
+ char *nextname;
+
+ assert (!lastcomp);
+
+ /* Find the name of the next pathname component */
+ nextname = index (path, '/');
+
+ if (nextname)
+ {
+ *nextname++ = '\0';
+ while (*nextname == '/')
+ nextname++;
+ if (*nextname == '\0')
+ {
+ /* These are the rules for filenames ending in /. */
+ nextname = 0;
+ lastcomp = 1;
+ mustbedir = 1;
+
+ }
+ else
+ lastcomp = 0;
+ }
+ else
+ lastcomp = 1;
+
+ node = 0;
+
+ /* Lookup the next pathname component. */
+ if (!lastcomp)
+ err = treefs_dir_lookup (dir, path, h->auth, 0, 0, &node);
+ else
+ /* ... and in this case, the last. Note that the S_IFREG only
+ applies in the case of O_CREAT, which is turned off for
+ directories anyway. */
+ err =
+ treefs_dir_lookup (dir, path, h->auth, flags, mode | S_IFREG, &node);
+
+ /* If we get an error we're done */
+ if (err == EAGAIN)
+ {
+ if (h->po->parent_port != MACH_PORT_NULL)
+ {
+ *retry = FS_RETRY_REAUTH;
+ *result = h->po->parent_port;
+ *result_type = MACH_MSG_TYPE_COPY_SEND;
+ if (!lastcomp)
+ strcpy (retry_name, nextname);
+ err = 0;
+ goto out;
+ }
+ else
+ /* The global filesystem root... .. == . */
+ {
+ err = 0;
+ node = dir;
+ treefs_node_ref (node);
+ }
+ }
+
+ if (err)
+ goto out;
+
+ /* If this is translated, start the translator (if necessary)
+ and return. */
+ /* The check for `node != dir' simplifies this code a great
+ deal. Such a translator should already have been started,
+ so there's no lossage in doing it this way. */
+ if ((!lastcomp || !(flags & O_NOTRANS))
+ && node != dir)
+ {
+ file_t dir_port = MACH_PORT_NULL, child_fsys;
+
+ /* Be very careful not to hold an inode lock while fetching
+ a translator lock and vice versa. */
+
+ mutex_unlock (&node->lock);
+ mutex_unlock (&dir->lock);
+
+ do
+ {
+ err =
+ treefs_node_get_active_trans (node, dir, h->po->parent_port,
+ &dir_port, &child_fsys);
+ if (err == 0 && child_fsys != MACH_PORT_NULL)
+ {
+ err =
+ fsys_getroot (child_fsys, dir_port,
+ MACH_MSG_TYPE_COPY_SEND,
+ h->auth->uids, h->auth->nuids,
+ h->auth->gids, h->auth->ngids,
+ lastcomp ? flags : 0,
+ retry, retry_name, result);
+ /* If we got MACH_SEND_INVALID_DEST or MIG_SERVER_DIED, then
+ the server is dead. Zero out the old control port and try
+ everything again. */
+ if (err == MACH_SEND_INVALID_DEST || err == EMIG_SERVER_DIED)
+ treefs_node_drop_active_trans (node, child_fsys);
+ }
+ }
+ while (err == MACH_SEND_INVALID_DEST || err == EMIG_SERVER_DIED);
+
+ if (err || child_fsys)
+ {
+ /* We're done; return to the user. If there are more
+ components after this name, be sure to append them to the
+ user's retry path. */
+ if (!err && !lastcomp)
+ {
+ strcat (retry_name, "/");
+ strcat (retry_name, nextname);
+ }
+
+ *result_type = MACH_MSG_TYPE_MOVE_SEND;
+
+ treefs_node_unref (dir);
+ treefs_node_unref (node);
+ if (dir_port)
+ mach_port_deallocate (mach_task_self (), dir_port);
+
+ return err;
+ }
+
+ /* We're here if we tried the translator check, and it
+ failed. Lock everything back, and make sure we do it
+ in the right order. */
+ if (strcmp (path, "..") != 0)
+ {
+ mutex_unlock (&node->lock);
+ mutex_lock (&dir->lock);
+ mutex_lock (&node->lock);
+ }
+ else
+ mutex_lock (&dir->lock);
+ }
+
+ if (treefs_node_type (node) == S_IFLNK
+ && !(lastcomp && (flags & (O_NOLINK|O_NOTRANS))))
+ /* Handle symlink interpretation */
+ {
+ unsigned nextname_len = nextname ? strlen (nextname) + 1 : 0;
+ /* max space we currently have for the sym link */
+ unsigned sym_len = path_buf_len - nextname_len - 1;
+
+ if (symlink_expansions++ > node->fsys->max_symlinks)
+ {
+ err = ELOOP;
+ goto out;
+ }
+
+ err = treefs_node_get_symlink (node, path_buf, &sym_len);
+ if (err == E2BIG)
+ /* Symlink contents + extra path won't fit in our buffer, so
+ reallocate it and try again. */
+ {
+ path_buf_len = sym_len + nextname_len + 1;
+ path_buf = alloca (path_buf_len);
+ err = treefs_node_get_symlink (node, path_buf, &sym_len);
+ }
+ if (err)
+ goto out;
+
+ if (nextname)
+ {
+ path_buf[sym_len] = '/';
+ bcopy (nextname, path_buf + sym_len + 1, nextname_len - 1);
+ }
+ path_buf[nextname_len + sym_len] = '\0';
+
+ if (path_buf[0] == '/')
+ {
+ /* Punt to the caller. */
+ *retry = FS_RETRY_MAGICAL;
+ *result = MACH_PORT_NULL;
+ strcpy (retry_name, path_buf);
+ goto out;
+ }
+
+ path = path_buf;
+ if (lastcomp)
+ {
+ lastcomp = 0;
+ /* Symlinks to nonexistent files aren't allowed to cause
+ creation, so clear the flag here. */
+ flags &= ~O_CREAT;
+ }
+ treefs_node_release (node);
+ node = 0;
+ }
+ else
+ {
+ /* Handle normal nodes */
+ path = nextname;
+ if (node == dir)
+ treefs_node_unref (dir);
+ else
+ treefs_node_release (dir);
+ if (!lastcomp)
+ {
+ dir = node;
+ node = 0;
+ }
+ else
+ dir = 0;
+ }
+ } while (path && *path);
+
+ gotit:
+ /* At this point, node is the node to return. */
+
+ if (mustbedir && !treefs_node_isdir (node))
+ err = ENOTDIR;
+ if (err)
+ goto out;
+
+ err = treefs_node_create_right (node, flags, h->po->parent_port, h->auth,
+ result);
+
+ out:
+ if (node)
+ {
+ if (dir == node)
+ treefs_node_unref (node);
+ else
+ treefs_node_release (node);
+ }
+ if (dir)
+ treefs_node_release (dir);
+ return err;
+}
diff --git a/libtreefs/fs-mutate.h b/libtreefs/fs-mutate.h
new file mode 100644
index 00000000..6ddec3fa
--- /dev/null
+++ b/libtreefs/fs-mutate.h
@@ -0,0 +1,30 @@
+/* Automagic type transformation for our mig interfaces
+
+ Copyright (C) 1994 Free Software Foundation
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* Only CPP macro definitions should go in this file. */
+
+#define FILE_INTRAN treefs_handle_t treefs_begin_using_handle_port (file_t)
+#define FILE_DESTRUCTOR treefs_end_using_handle_port (treefs_handle_t)
+
+#define IO_INTRAN treefs_handle_t treefs_begin_using_handle_port (io_t)
+#define IO_DESTRUCTOR treefs_end_using_handle_port (treefs_handle_t)
+
+#define FILE_IMPORTS import "mig-decls.h";
+#define IO_IMPORTS import "mig-decls.h";
+#define FSYS_IMPORTS import "mig-decls.h";
+#define IFSOCK_IMPORTS import "mig-decls.h";
diff --git a/libtreefs/fsys-getroot.c b/libtreefs/fsys-getroot.c
new file mode 100644
index 00000000..986938cf
--- /dev/null
+++ b/libtreefs/fsys-getroot.c
@@ -0,0 +1,144 @@
+/*
+
+ Copyright (C) 1995 Free Software Foundation, Inc.
+
+ Written by Miles Bader <miles@gnu.ai.mit.edu>
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <fcntl.h>
+
+#include <hurd/fsys.h>
+
+#include "treefs.h"
+
+error_t
+_treefs_s_fsys_getroot (struct treefs_fsys *fsys,
+ mach_port_t dotdot,
+ uid_t *uids, unsigned nuids,
+ uid_t *gids, unsigned ngids,
+ int flags, retry_type *retry, char *retry_name,
+ file_t *result, mach_msg_type_name_t *result_type)
+{
+ error_t err;
+ mode_t type;
+ struct treefs_node *root;
+ struct treefs_auth *auth;
+
+ flags &= O_HURD;
+
+ err = treefs_fsys_get_root (fsys, &root);
+ if (err)
+ return err;
+
+ if (!(flags & O_NOTRANS))
+ /* Try starting up any translator on the root node. */
+ {
+ fsys_t child_fsys;
+
+ do
+ {
+ err =
+ treefs_node_get_active_trans (root, 0, 0, &dotdot, &child_fsys);
+ if (err == 0 && child_fsys != MACH_PORT_NULL)
+ /* We think there's an active translator; try contacting it. */
+ {
+ err =
+ fsys_getroot (child_fsys, dotdot, MACH_MSG_TYPE_COPY_SEND,
+ uids, nuids, gids, ngids,
+ flags, retry, retry_name, result);
+ /* If we got MACH_SEND_INVALID_DEST or MIG_SERVER_DIED, then
+ the server is dead. Zero out the old control port and try
+ everything again. */
+ if (err == MACH_SEND_INVALID_DEST || err == EMIG_SERVER_DIED)
+ treefs_node_drop_active_trans (root, control_port);
+ }
+ }
+ while (err == MACH_SEND_INVALID_DEST || err == MIG_SERVER_DIED);
+
+ /* If we got a translator, or an error trying, return immediately. */
+ if (err || child_fsys)
+ {
+ if (!err && *result != MACH_PORT_NULL)
+ *result_type = MACH_MSG_TYPE_MOVE_SEND;
+ else
+ *result_type = MACH_MSG_TYPE_COPY_SEND;
+
+ if (!err)
+ mach_port_deallocate (mach_task_self (), dotdot);
+ treefs_node_unref (root);
+
+ return err;
+ }
+ }
+
+ mutex_lock (&root->lock);
+
+ type = treefs_node_type (root);
+ if (type == S_IFLNK && !(flags & (O_NOLINK | O_NOTRANS)))
+ /* Handle symlink interpretation */
+ {
+ int sym_len = 1000;
+ char path_buf[sym_len + 1], *path = path_buf;
+
+ err = treefs_node_get_symlink (root, path, &sym_len);
+ if (err == E2BIG)
+ /* Symlink contents won't fit in our buffer, so
+ reallocate it and try again. */
+ {
+ path = alloca (sym_len + 1);
+ err = treefs_node_get_symlink (node, path, &sym_len);
+ }
+
+ if (err)
+ goto out;
+
+ if (*path == '/')
+ {
+ *retry = FS_RETRY_MAGICAL;
+ *result = MACH_PORT_NULL;
+ *result_type = MACH_MSG_TYPE_COPY_SEND;
+ mach_port_deallocate (mach_task_self (), dotdot);
+ }
+ else
+ {
+ *retry = FS_RETRY_REAUTH;
+ *result = dotdot;
+ *result_type = MACH_MSG_TYPE_COPY_SEND;
+ }
+
+ strcpy (retry_name, path);
+ goto out;
+ }
+
+ err = treefs_node_create_auth (root, uids, nuids, gids, ngids, &auth);
+ if (err)
+ goto out;
+
+ *retry = FS_RETRY_NORMAL;
+ *retry_name = '\0';
+ *result_type = MACH_MSG_TYPE_MAKE_SEND;
+
+ err = treefs_node_create_right (root, dotdot, flags, auth, result);
+
+ treefs_node_auth_unref (root, auth);
+
+ out:
+ treefs_node_release (root);
+
+ return err;
+}
diff --git a/libtreefs/fsys-hooks.c b/libtreefs/fsys-hooks.c
new file mode 100644
index 00000000..cb7fcfc6
--- /dev/null
+++ b/libtreefs/fsys-hooks.c
@@ -0,0 +1,91 @@
+/* Default hooks for filesystems
+
+ Copyright (C) 1995 Free Software Foundation, Inc.
+
+ Written by Miles Bader <miles@gnu.ai.mit.edu>
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "treefs.h"
+
+/* Called to get the root node of the a filesystem, with a reference,
+ returning it in ROOT, or return an error if it can't be had. The default
+ hook just returns FSYS->root or an error if it's NULL. Note that despite
+ the similar name, this is very different from fsys_s_getroot! FSYS must
+ not be locked. */
+error_t
+_treefs_fsys_get_root (struct treefs_fsys *fsys, struct treefs_node **root)
+{
+ mutex_lock (&fsys->lock);
+ *root = fsys->root;
+ if (*root != NULL)
+ treefs_node_ref (*root);
+ mutex_unlock (&fsys->lock);
+
+ return *root ? 0 : EOPNOTSUPP;
+}
+
+/* Called on a filesystem to create a new node in that filesystem, returning
+ it in NODE. DIR, if non-NULL, is the nominal parent directory, and MODE
+ and CRED are the desired mode and user info respectively. This hook
+ should also call node_init_stat & node_init to initialize the various user
+ bits. */
+error_t
+_treefs_fsys_create_node (struct treefs_fsys *fsys,
+ struct treefs_node *dir,
+ mode_t mode, struct treefs_protid *cred,
+ struct treefs_node **node)
+{
+ error_t err = treefs_create_node (fsys, node);
+
+ if (err)
+ return err;
+
+ err = treefs_node_init_stat (*node, dir, mode, cred);
+ if (!err)
+ err = treefs_node_init (*node, dir, mode, cred);
+ if (S_ISDIR (mode))
+ {
+ treefs_dir_init (*node, dir, mode, cred);
+ treefs_mdir_init (*node, dir, mode, cred);
+ }
+ if (err)
+ {
+ /* There shouldn't be any other state to free at this point --
+ node_init_stat shouldn't do more than init the stat structure, and
+ if node_init fails, it should clean up after itself. */
+ treefs_free_node (*node);
+ return err;
+ }
+
+ return 0;
+}
+
+/* Called on a filesystem to destroy a node in that filesystem. This call
+ should *really* destroy it, i.e., it's only called once all references are
+ gone. */
+void
+_treefs_fsys_destroy_node (struct treefs_fsys *fsys, struct treefs_node *node)
+{
+ if (treefs_node_isdir (node))
+ {
+ treefs_mdir_finalize (node);
+ treefs_dir_finalize (node);
+ }
+ treefs_node_finalize (node);
+ treefs_free_node (node);
+}
diff --git a/libtreefs/fsys-startup.c b/libtreefs/fsys-startup.c
new file mode 100644
index 00000000..fcee3535
--- /dev/null
+++ b/libtreefs/fsys-startup.c
@@ -0,0 +1,36 @@
+/* fsys startup RPC
+
+ Copyright (C) 1995 Free Software Foundation, Inc.
+
+ Written by Miles Bader <miles@gnu.ai.mit.edu>
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+error_t
+treefs_S_fsys_startup (mach_port_t child_boot_port, mach_port_t control_port,
+ mach_port_t *real, mach_msg_type_name_t *real_type)
+{
+ error_t err;
+ struct port_info *child_boot =
+ ports_check_port_type (child_boot_port, PT_TRANSBOOT);
+
+ assert (child_boot); /* XXX deal with exec server boot */
+ err = fshelp_handle_fsys_startup (child_boot, control_port, real, real_type);
+ ports_done_with_port (child_boot);
+
+ return err;
+}
diff --git a/libtreefs/fsys.c b/libtreefs/fsys.c
new file mode 100644
index 00000000..459d0d3b
--- /dev/null
+++ b/libtreefs/fsys.c
@@ -0,0 +1,127 @@
+/*
+
+ Copyright (C) 1995 Free Software Foundation, Inc.
+
+ Written by Miles Bader <miles@gnu.ai.mit.edu>
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "treefs.h"
+
+/* ---------------------------------------------------------------- */
+
+/* Create a basic node, with one reference and no user-specific fields
+ initialized, and return it in NODE */
+error_t
+treefs_create_node (struct treefs_fsys *fsys, struct treefs_node **node)
+{
+ struct treefs_node *n = malloc (sizeof (struct treefs_node));
+
+ if (n == NULL)
+ return ENOMEM;
+
+ n->fsys = fsys;
+ n->refs = 1;
+ n->light_refs = 0;
+ n->hooks = fsys->hooks;
+ n->children = NULL;
+ n->u = NULL;
+ mutex_init (&n->lock);
+ fshelp_init_trans_link (&n->active_trans);
+ fshelp_lock_init (&n->lock_box);
+
+ *node = n;
+ return 0;
+}
+
+/* Immediately destroy NODE, with no user-finalization. */
+error_t
+treefs_free_node (struct treefs_node *node)
+{
+ free (node);
+}
+
+/* ---------------------------------------------------------------- */
+
+/* Returns a new filesystem in FSYS. */
+error_t
+treefs_create_fsys (struct port_bucket *port_bucket,
+ treefs_hook_vector_t hook_overrides,
+ struct treefs_fsys **fsys)
+{
+ treefs_hook_vector_t hooks = treefs_default_hooks;
+
+ if (hook_overrides)
+ {
+ hooks = treefs_hooks_clone (hooks);
+ treefs_hooks_override (hooks, hooks_overrides);
+ }
+
+ *fsys =
+ ports_allocate_port (port_bucket, sizeof (struct trivfs_control),
+ treefs_fsys_port_class);
+ if (*fsys == NULL)
+ return ENOMEM;
+
+ mutex_init (&(*fsys)->lock);
+ (*fsys)->root = NULL;
+
+ (*fsys)->underlying_port = MACH_PORT_NULL;
+ bzero (&(*fsys)->underlying_stat, sizeof (struct stat));
+
+ (*fsys)->flags = treefs_default_flags;
+ (*fsys)->max_symlinks = treefs_default_max_symlinks;
+ (*fsys)->sync_interval = treefs_default_sync_interval;
+
+ (*fsys)->fs_type = treefs_default_fsys_type;
+ (*fsys)->fs_id = getpid();
+
+ (*fsys)->hooks = hooks;
+
+ (*fsys)->port_bucket = port_bucket;
+ (*fsys)->protid_ports_class = treefs_protid_port_class;
+
+ (*fsys)->u = NULL;
+
+ return 0;
+}
+
+
+void ACKACKACK()
+{
+ /* Create a fake root node to bootstrap the filesystem. */
+ err = treefs_create_node(*fsys, &fake_root);
+ if (err)
+ goto barf;
+
+ /* Remember stat info for the node we're mounted on. */
+ bzero (&(*fsys)->underlying_stat, sizeof (struct stat));
+ file_stat (realnode, &(*fsys)->underlying_stat);
+
+ /* Note that it points to *FSYS, but *FSYS's root doesn't point to it...
+ If the user wants this to be the real root, it's his responsility to
+ initialize if further and install it. */
+ fake_root->fsys = *fsys;
+ bcopy (&(*fsys)->underlying_stat, &fake_root->stat);
+ err = treefs_fsys_init (fake_root);
+ if (err)
+ goto barf;
+
+ /* See if the silly user has in fact done so. */
+ if ((*fsys)->root != fake_root)
+ treefs_free_node (fake_root);
+}
diff --git a/libtreefs/hooks.c b/libtreefs/hooks.c
new file mode 100644
index 00000000..b8ec103f
--- /dev/null
+++ b/libtreefs/hooks.c
@@ -0,0 +1,59 @@
+/* Functions for manipulating hook vectors.
+
+ Copyright (C) 1995 Free Software Foundation, Inc.
+
+ Written by Miles Bader <miles@gnu.ai.mit.edu>
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "treefs.h"
+
+#define HV_SIZE (sizeof (void (*)()) * TREEFS_NUM_HOOKS)
+
+/* Returns a copy of the treefs hook vector HOOKS, or a zero'd vector if HOOKS
+ is NULL. If HOOKS is NULL, treefs_default_hooks is used. If a memory
+ allocation error occurs, NULL is returned. */
+treefs_hook_vector_t
+treefs_hooks_clone (treefs_hook_vector_t hooks)
+{
+ treefs_hook_vector_t clone = malloc (HV_SIZE);
+ if (clone != NULL)
+ {
+ if (hooks == NULL)
+ hooks = treefs_default_hooks;
+ bcopy (hooks, clone, HV_SIZE);
+ }
+ return clone;
+}
+
+/* Copies each non-NULL entry in OVERRIDES into HOOKS. */
+void
+treefs_hooks_override (treefs_hook_vector_t hooks,
+ treefs_hook_vector_t overrides)
+{
+ int num;
+ for (num = 0; num < TREEFS_NUM_HOOKS; num++)
+ if (overrides[num] != NULL)
+ hooks[num] = overrides[num];
+}
+
+/* Sets the hook NUM in HOOKS to HOOK. */
+void
+treefs_hooks_set (treefs_hook_vector_t hooks, unsigned num, void (*hook)())
+{
+ hooks[num] = hook;
+}
diff --git a/libtreefs/mdir.c b/libtreefs/mdir.c
new file mode 100644
index 00000000..ddc1516a
--- /dev/null
+++ b/libtreefs/mdir.c
@@ -0,0 +1,92 @@
+/* Low-level directory manipulation functions
+
+ Copyright (C) 1995 Free Software Foundation, Inc.
+
+ Written by Miles Bader <miles@gnu.ai.mit.edu>
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* Low level dir management routines. If called on a non-dir, ENOTDIR is
+ returned. */
+
+/* Add CHILD to DIR as NAME, replacing any existing entry. If OLD_CHILD is
+ NULL, and NAME already exists in dir, EEXIST is returned, otherwise, any
+ previous child is replaced and returned in OLD_CHILD. DIR should be
+ locked. */
+error_t
+treefs_mdir_add (struct treefs_node *dir, char *name,
+ struct treefs_node *child, struct treefs_node **old_child)
+{
+ if (!treefs_node_isdir (dir))
+ return ENOTDIR;
+ else
+ {
+ if (dir->children == NULL)
+ {
+ dir->children = treefs_make_node_list ();
+ if (dir->children == NULL)
+ return ENOMEM;
+ }
+ return treefs_node_list_add (dir->children, name, child, old_child);
+ }
+}
+
+/* Remove any entry in DIR called NAME. If there is no such entry, ENOENT is
+ returned. If OLD_CHILD is non-NULL, any removed entry is returned in it.
+ DIR should be locked. */
+error_t
+treefs_mdir_remove (struct treefs_node *dir, char *name,
+ struct treefs_node *old_child)
+{
+ if (!treefs_node_isdir (dir))
+ return ENOTDIR;
+ else if (dir->children == NULL)
+ /* Normally this shouldn't happen. */
+ return ENOENT;
+ else
+ return treefs_node_list_remove (dir->children, name, old_child);
+}
+
+/* Returns in CHILD any entry called NAME in DIR, or NULL (and ENOENT) if
+ there isn't such. DIR should be locked. */
+error_t
+treefs_mdir_get (struct treefs_node *dir, char *name,
+ struct treefs_node **child)
+{
+ if (!treefs_node_isdir (dir))
+ return ENOTDIR;
+ else if (dir->children == NULL)
+ /* Normally this shouldn't happen. */
+ return ENOENT;
+ else
+ return treefs_node_list_get (dir->children, name, child);
+}
+
+/* Call FUN on each child of DIR; if FUN returns a non-zero value at any
+ point, stop iterating and return that value immediately. */
+error_t
+treefs_mdir_for_each (struct treefs_node *dir,
+ error_t (*fun)(char *name, struct treefs_node *child))
+{
+ if (!treefs_node_isdir (dir))
+ return ENOTDIR;
+ else if (dir->children == NULL)
+ /* Normally this shouldn't happen. */
+ return 0;
+ else
+ return treefs_node_list_for_each (dir->children, fun);
+}
diff --git a/libtreefs/mig-decls.h b/libtreefs/mig-decls.h
new file mode 100644
index 00000000..0d051e9c
--- /dev/null
+++ b/libtreefs/mig-decls.h
@@ -0,0 +1,41 @@
+/* Type decls for mig-produced server stubs
+
+ Copyright (C) 1995 Free Software Foundation, Inc.
+
+ Written by Miles Bader <miles@gnu.ai.mit.edu>
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "treefs.h"
+
+/* For mig */
+typedef struct treefs_handle *treefs_handle_t;
+
+extern inline
+treefs_handle_t treefs_begin_using_handle_port(mach_port_t port)
+{
+ return
+ (struct treefs_handle *)
+ ports_lookup_port (0, port, treefs_fsys_port_class);
+}
+
+extern inline void
+treefs_end_using_handle_port (treefs_handle_t handle)
+{
+ if (handle != NULL)
+ ports_port_deref (&handle->pi);
+}
diff --git a/libtreefs/nlist.c b/libtreefs/nlist.c
new file mode 100644
index 00000000..326bb0f8
--- /dev/null
+++ b/libtreefs/nlist.c
@@ -0,0 +1,70 @@
+/* Functions for dealing with node lists
+
+ Copyright (C) 1995 Free Software Foundation, Inc.
+
+ Written by Miles Bader <miles@gnu.ai.mit.edu>
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "treefs.h"
+
+/* ---------------------------------------------------------------- */
+struct treefs_node_list
+{
+ unsigned short num_nodes, nodes_alloced;
+
+};
+
+/* Return a new node list, or NULL if a memory allocation error occurs. */
+struct treefs_node_list *
+treefs_make_node_list ()
+{
+ struct treefs_node_list *nl = malloc (sizeof (struct treefs_node_list));
+ if (!nl)
+ return NULL;
+
+ nl->nodes_alloced = 0;
+ nl->num_nodes = 0;
+
+ return nl;
+}
+
+/* Add NODE to LIST as NAME, replacing any existing entry. If OLD_NODE is
+ NULL, and an entry NAME already exists, EEXIST is returned, otherwise, any
+ previous child is replaced and returned in OLD_NODE. */
+error_t
+treefs_node_list_add (struct treefs_node_list *list, char *name,
+ struct treefs_node *node, struct treefs_node **old_node)
+{
+
+}
+
+/* Remove any entry in LIST called NAME. If there is no such entry, ENOENT is
+ returned. If OLD_NODE is non-NULL, any removed entry is returned in it. */
+error_t
+treefs_node_list_remove (struct treefs_node_list *list, char *name,
+ struct treefs_node **old_node)
+{
+}
+
+/* Returns in NODE any entry called NAME in LIST, or NULL (and ENOENT) if
+ there isn't such. */
+error_t
+treefs_node_list_get (struct treefs_node_list *list, char *name,
+ struct treefs_node **node)
+{
+}
diff --git a/libtreefs/node-hooks.c b/libtreefs/node-hooks.c
new file mode 100644
index 00000000..faffcd6a
--- /dev/null
+++ b/libtreefs/node-hooks.c
@@ -0,0 +1,176 @@
+/* Default hooks for nodes
+
+ Copyright (C) 1995 Free Software Foundation, Inc.
+
+ Written by Miles Bader <miles@gnu.ai.mit.edu>
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "treefs.h"
+
+/* ---------------------------------------------------------------- */
+/* These default hooks depend on stat information being correct. */
+
+/* Returns the type of NODE, as an S_IFMT value (e.g., S_IFDIR). The
+ default routine just looks at NODE's stat mode. */
+int
+_treefs_node_type (struct treefs_node *node)
+{
+ return node->stat.st_mode & S_IFMT;
+}
+
+/* Return TRUE if NODE is `unlinked' -- that is, can be deleted when all
+ (in-memory) references go away. */
+int
+_treefs_node_unlinked (struct treefs_node *node)
+{
+ return node->stat.st_nlinks == 0;
+}
+
+/* Changes the link count of NODE by CHANGE; if any error is returned, the
+ operation trying to change the link count will fail, so filesystems that
+ don't support real links can restrict it to 1 or 0. This is mostly used
+ by the in-core directory code when it makes a link. The default hook uses
+ the link field of NODE's stat entry. */
+error_t
+_treefs_node_mod_link_count (struct treefs_node *node, int change)
+{
+ node->stat.st_nlinks += change;
+}
+
+
+/* ---------------------------------------------------------------- */
+/* These default hooks depend on stat information being correct. */
+
+/* Returns the user and group that a newly started translator should be
+ authenticated as. The default just returns the owner/group of NODE. */
+error_t
+_treefs_node_get_trans_auth (struct treefs_node *node, uid_t *uid, gid_t *gid)
+{
+ *uid = node->stat.st_uid;
+ *gid = node->stat.st_gid;
+ return 0;
+}
+
+/* Check to see is the user identified by AUTH is permitted to do
+ operation OP on node NP. Op is one of S_IREAD, S_IWRITE, or S_IEXEC.
+ Return 0 if the operation is permitted and EACCES if not. */
+error_t
+_treefs_node_access (struct treefs_node *node,
+ int op, struct treefs_auth *auth)
+{
+ int gotit;
+ if (diskfs_auth_has_uid (auth, 0))
+ gotit = 1;
+ else if (auth->nuids == 0 && (node->stat.st_mode & S_IUSEUNK))
+ gotit = node->stat.st_mode & (op << S_IUNKSHIFT);
+ else if (!treefs_node_owned (node, auth))
+ gotit = node->stat.st_mode & op;
+ else if (treefs_auth_in_group (auth, node->stat.st_gid))
+ gotit = node->stat.st_mode & (op >> 3);
+ else
+ gotit = node->stat.st_mode & (op >> 6);
+ return gotit ? 0 : EACCES;
+}
+
+/* Check to see if the user identified by AUTH is permitted to do owner-only
+ operations on node NP; if so, return 0; if not, return EPERM. */
+error_t
+_treefs_node_owned (struct treefs_node *node, struct treefs_auth *auth)
+{
+ /* Permitted if the user is the owner, superuser, or if the user
+ is in the group of the file and has the group ID as their user
+ ID. (This last is colloquially known as `group leader'.) */
+ if (treefs_auth_has_uid (auth, node->stat.st_uid)
+ || treefs_auth_has_uid (auth, 0)
+ || (treefs_auth_in_group (auth, node->stat.st_gid)
+ && treefs_auth_has_uid (auth, node->stat.st_gid)))
+ return 0;
+ else
+ return EPERM;
+}
+
+/* ---------------------------------------------------------------- */
+
+error_t
+_treefs_node_init_stat (struct treefs_node *node, struct treefs_node *dir,
+ mode_t mode, struct treefs_auth *auth)
+{
+ if (auth->nuids)
+ node->stat.st_uid = auth->uids[0];
+ else
+ {
+ mode &= ~S_ISUID;
+ if (dir)
+ node->stat.st_uid = dir->stat.st_uid;
+ else
+ node->stat.st_uid = -1; /* XXX */
+ }
+
+ if (dir && diskfs_ingroup (dir->stat.st_gid, auth))
+ node->stat.st_gid = dir->stat.st_gid;
+ else if (auth->ngids)
+ node->stat.st_gid = auth->gids[0];
+ else
+ {
+ mode &= ~S_ISGID;
+ if (dir)
+ node->stat.st_gid = dir->stat.st_gid;
+ else
+ node->stat.st_gid = -1; /* XXX */
+ }
+
+ node->stat.st_rdev = 0;
+ node->stat.st_nlink = 0;
+ node->stat.st_mode = mode;
+
+ node->stat.st_blocks = 0;
+ node->stat.st_size = 0;
+ node->stat.st_flags = 0;
+
+ return 0;
+}
+
+/* ---------------------------------------------------------------- */
+
+/* Called when the new peropen structure PO is made for NODE, with the
+ authorization in AUTH, opened with the flags FLAGS. If an error is
+ returned, the open will fail with that error. The default hook does
+ explicit authorization checks against AUTH using treefs_node_access, and
+ otherwise does nothing. */
+error_t
+_treefs_init_peropen (struct treefs_node *node, struct treefs_peropen *po,
+ int flags, struct treefs_auth *auth)
+{
+ error_t err;
+
+ if (flags & O_READ)
+ err = treefs_node_access (node, S_IREAD, auth);
+ if (!err && (flags & O_EXEC))
+ err = treefs_node_access (node, S_IEXEC, auth);
+ if (!err && (flags & O_WRITE))
+ {
+ if (type == S_IFDIR)
+ err = EISDIR;
+ else if (auth->po->node->fsys->readonly)
+ err = EROFS;
+ else
+ err = treefs_node_access (node, S_IWRITE, auth);
+ }
+
+ return err;
+}
diff --git a/libtreefs/rights.c b/libtreefs/rights.c
new file mode 100644
index 00000000..f803b029
--- /dev/null
+++ b/libtreefs/rights.c
@@ -0,0 +1,96 @@
+/* Functions for making send rights in various ways
+
+ Copyright (C) 1995 Free Software Foundation, Inc.
+
+ Written by Miles Bader <miles@gnu.ai.mit.edu>
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* Return in PORT a send right for a new protid, pointing at the peropen PO,
+ with rights initialized from AUTH. */
+error_t
+treefs_peropen_create_right (struct treefs_peropen *po,
+ struct treefs_auth *auth,
+ mach_port_t *port)
+{
+ struct treefs_node *node = po->node;
+ struct treefs_fsys *fsys = node->fsys;
+ struct treefs_handle *handle =
+ ports_allocate_port (fsys->port_bucket,
+ sizeof (struct treefs_handle),
+ fsys->handle_port_class);
+
+ if (handle == NULL)
+ return MACH_PORT_NULL;
+
+ handle->po = po;
+ po->refs++;
+ handle->auth = auth;
+ auth->refs++;
+
+ err = treefs_node_init_handle (node, handle);
+ if (err)
+ {
+ po->refs--;
+ auth->refs--;
+ }
+
+ *port = ports_get_right (handle);
+
+ return 0;
+}
+
+/* Return in PORT a send right for a new handle and a new peropen, pointing
+ at NODE, with rights initialized from AUTH. FLAGS and PARENT_PORT are used
+ to initialize the corresponding fields in the new peropen. */
+error_t
+treefs_node_create_right (struct treefs_node *node, int flags,
+ mach_port_t parent_port, struct treefs_auth *auth,
+ mach_port_t *port)
+{
+ struct treefs_peropen *po = malloc (sizeof (struct treefs_peropen));
+
+ if (po == NULL)
+ return ENOMEM;
+
+ /* Initialize the peropen structure. */
+ po->refs = 0;
+ po->node = node;
+ po->open_flags = flags;
+ po->user_lock_state = LOCK_UN;
+ po->parent_port = parent_port;
+ if (parent_port != MACH_PORT_NULL)
+ mach_port_mod_refs (mach_task_self (),
+ parent_port, MACH_PORT_RIGHT_SEND, 1);
+
+ treefs_node_ref (node);
+
+ err = treefs_node_init_peropen (node, po, flags, auth);
+ if (err)
+ goto puke;
+
+ err = treefs_peropen_create_right (po, auth, port);
+ if (err)
+ goto puke;
+
+ return 0;
+
+ puke:
+ treefs_node_unref (node);
+ free (po);
+ return err;
+}
diff --git a/libtreefs/s-dir.c b/libtreefs/s-dir.c
new file mode 100644
index 00000000..08c4eb99
--- /dev/null
+++ b/libtreefs/s-dir.c
@@ -0,0 +1,112 @@
+/* File_t rpc stubs for directories; see <hurd/fs.defs> for more info
+
+ Copyright (C) 1995 Free Software Foundation, Inc.
+
+ Written by Miles Bader <miles@gnu.ai.mit.edu>
+
+ Note that since the user overrides the builtin routines via hook vectors
+ instead of declaring his own stubs, it doesn't make a lot of sense to put
+ these routines in separate files like diskfs. This way should compile
+ faster; with dynamic libraries it won't matter in any case.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+error_t
+treefs_S_dir_notice_changes (struct treefs_protid *cred,
+ mach_port_t notify)
+{
+ if (cred == NULL)
+ return EOPNOTSUPP;
+ return treefs_s_dir_notice_changes (cred, notify);
+}
+
+error_t
+treefs_S_dir_link (struct treefs_protid *dir_cred,
+ struct treefs_protid *file_cred,
+ char *name)
+{
+ if (cred == NULL)
+ return EOPNOTSUPP;
+ return treefs_s_dir_link (dir_cred, file_cred, name);
+}
+
+error_t
+treefs_S_dir_lookup (struct treefs_protid *cred,
+ char *path, int flags, mode_t mode,
+ enum retry_type *retry, char *retry_name,
+ file_t *result, mach_msg_type_name_t *result_type)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+ return treefs_s_dir_lookup (cred, path, flags, mode, retry, retry_name,
+ result, result_type);
+}
+
+error_t
+treefs_S_dir_mkdir (struct treefs_protid *cred, char *name, mode_t mode)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+ return treefs_s_dir_mkdir (cred, name, mode);
+}
+
+error_t
+treefs_S_dir_mkfile (struct treefs_protid *cred,
+ int flags, mode_t mode,
+ mach_port_t *newnode, mach_msg_type_name_t *newnode_type)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+ return treefs_s_dir_mkfile (cred, flags, mode, newnode, newnode_type);
+}
+
+error_t
+treefs_S_dir_readdir (struct treefs_protid *cred,
+ char **data, unsigned *datacnt,
+ int entry, int num_entries,
+ vm_size_t bufsiz, int *amt)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+ return treefs_s_dir_readdir (cred, data, datacnt,
+ entry, num_entries, bufsiz, amt);
+}
+
+error_t
+treefs_S_dir_rename (struct treefs_protid *cred, char *name,
+ struct treefs_protid *to_cred, char *to_name)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+ return treefs_s_dir_rename (cred, name, to_cred, to_name);
+}
+
+error_t
+treefs_S_dir_rmdir (struct treefs_protid *cred, char *name)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+ return treefs_s_dir_rmdir (cred, name);
+}
+
+error_t
+treefs_S_dir_unlink (struct treefs_protid *cred, char *name)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+ return treefs_s_dir_unlink (cred, name);
+}
diff --git a/libtreefs/s-file.c b/libtreefs/s-file.c
new file mode 100644
index 00000000..cd9144da
--- /dev/null
+++ b/libtreefs/s-file.c
@@ -0,0 +1,233 @@
+/* File_t rpc stubs; see <hurd/fs.defs> for more info
+
+ Copyright (C) 1995 Free Software Foundation, Inc.
+
+ Written by Miles Bader <miles@gnu.ai.mit.edu>
+
+ Note that since the user overrides the builtin routines via hook vectors
+ instead of declaring his own stubs, it doesn't make a lot of sense to put
+ these routines in separate files (like diskfs). This way should compile
+ faster, with dynamic libraries it won't matter in any case.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+error_t
+treefs_S_file_check_access (struct treefs_protid *cred, int *type)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+ return treefs_s_file_check_access (cred, type);
+}
+
+error_t
+treefs_S_file_chauthor (struct treefs_protid *cred, uid_t author)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+ return treefs_s_file_chauthor (cred, author);
+}
+
+error_t
+treefs_S_file_chflags (struct treefs_protid *cred, int flags)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+ return treefs_s_file_chflags (cred, flags);
+}
+
+error_t
+treefs_S_file_notice_changes (struct treefs_protid *cred, mach_port_t notify)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+ return treefs_s_file_notice_changes (cred, notify);
+}
+
+error_t
+treefs_S_file_chmod (struct treefs_protid *cred, mode_t mode)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+ mode &= ~(S_IFMT | S_ISPARE);
+ return treefs_s_file_chmod (cred, mode);
+}
+
+error_t
+treefs_S_file_chown (struct treefs_protid *cred, uid_t uid, gid_t gid)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+ return treefs_s_file_chown (cred, uid, gid);
+}
+
+error_t
+treefs_S_file_exec (struct treefs_protid *cred,
+ task_t task, int flags,
+ char *argv, unsigned argv_len,
+ char *envp, unsigned envp_len,
+ mach_port_t *fds, unsigned fds_len,
+ mach_port_t *ports, unsigned ports_len,
+ int *ints, unsigned ints_len,
+ mach_port_t *dealloc, unsigned dealloc_len,
+ mach_port_t *destroy, unsigned destroy_len)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+ return treefs_s_file_exec (cred, task, flags, argv, argv_len, envp, envp_len,
+ fds, fds_len, ports, ports_len, ints, ints_len,
+ dealloc, dealloc_len, destroy, destroy_len);
+}
+
+error_t
+treefs_S_file_get_translator (struct treefs_protid *cred,
+ char **trans, unsigned *trans_len)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+ return treefs_s_file_get_translator (cred, trans, trans_len);
+}
+
+error_t
+treefs_S_file_get_translator_cntl (struct treefs_protid *cred,
+ mach_port_t *ctl,
+ mach_msg_type_name_t *ctl_type)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+ return treefs_s_file_get_translator_cntl (cred, ctl, ctl_type);
+}
+
+error_t
+treefs_S_file_getcontrol (struct treefs_protid *cred,
+ mach_port_t *control,
+ mach_msg_type_name_t *control_type)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+ return treefs_s_file_getcontrol (cred, control, control_type);
+}
+
+error_t
+treefs_S_file_getfh (struct treefs_protid *cred,
+ char **data, unsigned *data_len)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+ return treefs_s_file_getfh (cred, data, data_len);
+}
+
+error_t
+treefs_S_file_getlinknode (struct treefs_protid *cred,
+ file_t *port, mach_msg_type_name_t *port_type)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+ return treefs_s_file_t (cred, port, port_type);
+}
+
+error_t
+treefs_S_file_invoke_translator (struct treefs_protid *cred,
+ int flags,
+ retry_type *retry, char *retry_name,
+ mach_port_t *retry_port,
+ mach_msg_type_name_t *retry_port_type)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+ return treefs_s_file_invoke_translator (cred, flags, retry, retry_name,
+ retry_port, retry_port_type);
+}
+
+error_t
+treefs_S_file_lock_stat (struct treefs_protid *cred,
+ int *self_status, int *other_status)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+ return treefs_s_file_lock_stat (cred, self_status, other_status);
+}
+
+error_t
+treefs_S_file_lock (struct treefs_protid *cred, int flags)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+ return treefs_s_file_lock (cred, flags);
+}
+
+error_t
+treefs_S_file_pathconf (struct treefs_protid *cred, int name, int *value)
+ {
+ if (!cred)
+ return EOPNOTSUPP;
+ return treefs_s_file_pathconf (cred, name, value);
+}
+
+error_t
+treefs_S_file_set_translator (struct treefs_protid *cred,
+ int passive_flags, int active_flags,
+ int killtrans_flags,
+ char *passive, unsigned passive_len,
+ fsys_t active)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+ return treefs_s_file_set_translator (cred, passive_flags, active_flags,
+ killtrans_flags, passive, passive_len,
+ active);
+}
+
+error_t
+treefs_S_file_statfs (struct treefs_protid *cred, fsys_statfsbuf_t *statbuf)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+ return treefs_s_file_statfs (cred, statbuf);
+}
+
+error_t
+treefs_S_file_sync (struct treefs_protid *cred, int wait)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+ return treefs_s_file_sync (cred, wait);
+}
+
+error_t
+treefs_S_file_syncfs (struct treefs_protid *cred, int wait, int recurse)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+ return treefs_s_file_syncfs (cred, wait, recurse);
+}
+
+error_t
+treefs_S_file_set_size (struct treefs_protid *cred, off_t size)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+ return treefs_s_file_set_size (cred, size);
+}
+
+error_t
+treefs_S_file_utimes (struct treefs_protid *cred,
+ time_value_t atime, time_value_t mtime)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+ return treefs_s_file_utimes (cred, atime, mtime);
+}
diff --git a/libtreefs/s-fsys.c b/libtreefs/s-fsys.c
new file mode 100644
index 00000000..c2b1835b
--- /dev/null
+++ b/libtreefs/s-fsys.c
@@ -0,0 +1,77 @@
+/* fsys_t rpc stubs; see <hurd/fsys.defs> for more info
+
+ Copyright (C) 1995 Free Software Foundation, Inc.
+
+ Written by Miles Bader <miles@gnu.ai.mit.edu>
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "treefs.h"
+
+#define CALL_FSYS_HOOK(hook, fsys_port, args...) \
+{ \
+ error_t _err; \
+ struct treefs_fsys *_fsys = (struct treefs_fsys *) \
+ ports_lookup_port (0, fsys_port, treefs_fsys_port_class); \
+ if (!_fsys) \
+ return EOPNOTSUPP; \
+ err = hook(_fsys , ##args); \
+ ports_port_deref (&_fsys->pi); \
+ return _err; \
+}
+
+error_t
+treefs_S_fsys_getroot (fsys_t fsys_port, mach_port_t dotdot,
+ uid_t *uids, unsigned nuids,
+ gid_t *gids, unsigned ngids,
+ int flags, retry_type *retry, char *retry_name,
+ file_t *result, mach_msg_type_name_t *result_type)
+{
+ CALL_FSYS_HOOK(treefs_s_fsys_getroot, fsys_port, dotdot, uids, nuids, gids,
+ ngids, flags, retry, retry_name, result, result_type);
+}
+
+error_t
+treefs_S_fsys_set_options (fsys_t fsys_port,
+ char *data, unsigned len, int recurse)
+{
+ CALL_FSYS_HOOK(treefs_s_fsys_set_options, fsys_port, data, len, recurse);
+}
+
+error_t
+treefs_S_fsys_goaway (fsys_t fsys_port, int flags)
+{
+ CALL_FSYS_HOOK(treefs_s_fsys_goaway, fsys_port, flags);
+}
+
+error_t
+treefs_S_fsys_getfile (mach_port_t fsys_port,
+ uid_t *gen_uids, unsigned ngen_uids,
+ gid_t *gen_gids, unsigned ngen_gids,
+ char *handle, unsigned handle_len,
+ mach_port_t *file, mach_msg_type_name_t *file_type)
+{
+ CALL_FSYS_HOOK(treefs_s_fsys_getfile, fsys_port, gen_uids, ngen_uids,
+ gen_gids, ngen_gids, handle, handle_len, file, file_type);
+}
+
+error_t
+treefs_S_fsys_syncfs (fsys_t fsys_port, int wait, int recurse)
+{
+ CALL_FSYS_HOOK(treefs_s_fsys_syncfs, fsys_port, wait, recurse);
+}
+
diff --git a/libtreefs/s-io.c b/libtreefs/s-io.c
new file mode 100644
index 00000000..6fdc504a
--- /dev/null
+++ b/libtreefs/s-io.c
@@ -0,0 +1,284 @@
+/* io_t rpc stubs; see <hurd/io.defs> for more info
+
+ Copyright (C) 1995 Free Software Foundation, Inc.
+
+ Written by Miles Bader <miles@gnu.ai.mit.edu>
+
+ Note that since the user overrides the builtin routines via hook vectors
+ instead of declaring his own stubs, it doesn't make a lot of sense to put
+ these routines in separate files (like diskfs). This way should compile
+ faster, with dynamic libraries it won't matter in any case.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+error_t
+treefs_S_io_get_icky_async_id (struct treefs_protid *cred,
+ mach_port_t *id, mach_msg_type_name_t *id_type)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+ return treefs_s_io_get_icky_async_id (cred, id, id_type);
+}
+
+error_t
+treefs_S_io_async (struct treefs_protid *cred,
+ mach_port_t notify,
+ mach_port_t *id, mach_msg_type_name_t *id_type)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+ return treefs_s_io_async (cred, notify, id, id_type);
+}
+
+error_t
+treefs_S_io_duplicate (struct treefs_protid *cred,
+ mach_port_t *port,
+ mach_msg_type_name_t *port_type)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+ return treefs_s_io_duplicate (cred, port, port_type);
+}
+
+error_t
+treefs_S_io_get_conch (struct treefs_protid *cred)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+ return treefs_s_io_get_conch (cred);
+}
+
+error_t
+treefs_S_io_interrupt (struct treefs_protid *cred)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+ return treefs_s_io_interrupt (cred);
+}
+
+error_t
+treefs_S_io_map_cntl (struct treefs_protid *cred,
+ memory_object_t *ctlobj,
+ mach_msg_type_name_t *ctlobj_type)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+ return treefs_s_io_map_cntl (cred, ctlobj, ctlobj_type);
+}
+
+error_t
+treefs_S_io_map (struct treefs_protid *cred,
+ memory_object_t *rdobj, mach_msg_type_name_t *rd_type,
+ memory_object_t *wrobj, mach_msg_type_name_t *wr_type)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+ return treefs_s_io_map (cred, rdobj, rd_type, wrobj, wr_type);
+}
+
+error_t
+treefs_S_io_get_openmodes (struct treefs_protid *cred, int *bits)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+ return treefs_s_io_get_openmodes (cred, bits);
+}
+
+error_t
+treefs_S_io_clear_some_openmodes (struct treefs_protid *cred, int bits)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+ return treefs_s_io_clear_some_openmodes (cred, bits);
+}
+
+error_t
+treefs_S_io_set_some_openmodes (struct treefs_protid *cred, int bits)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+ return treefs_s_io_set_some_openmodes (cred, bits);
+}
+
+error_t
+treefs_S_io_set_all_openmodes (struct treefs_protid *cred, int bits)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+ return treefs_s_io_set_all_openmodes (cred, bits);
+}
+
+error_t
+treefs_S_io_get_owner (struct treefs_protid *cred, pid_t *owner)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+ return treefs_s_io_get_owner (cred, owner);
+}
+
+error_t
+treefs_S_io_mod_owner (struct treefs_protid *cred, pid_t owner)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+ return treefs_s_io_mod_owner (cred, owner);
+}
+
+error_t
+treefs_S_io_prenotify (struct treefs_protid *cred,
+ vm_offset_t start, vm_offset_t end)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+ return treefs_s_io_prenotify (cred, start, end);
+}
+
+error_t
+treefs_S_io_read (struct treefs_protid *cred,
+ char **data,
+ mach_msg_type_number_t *data_len,
+ off_t offset,
+ mach_msg_type_number_t max)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+ return treefs_s_io_read (cred, data, data_len, offset, max);
+}
+
+error_t
+treefs_S_io_readable (struct treefs_protid *cred,
+ mach_msg_type_number_t *amount)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+ return treefs_s_io_readable (cred, amount);
+}
+
+error_t
+treefs_S_io_reauthenticate (struct treefs_protid *cred, mach_port_t rend_port)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+ return treefs_s_io_reauthenticate (cred, rend_port);
+}
+
+error_t
+treefs_S_io_release_conch (struct treefs_protid *cred)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+ return treefs_s_io_release_conch (cred);
+}
+
+error_t
+treefs_S_io_restrict_auth (struct treefs_protid *cred,
+ mach_port_t *newport,
+ mach_msg_type_name_t *newport_type,
+ uid_t *uids, unsigned nuids,
+ gid_t *gids, unsigned ngids)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+ return treefs_s_io_restrict_auth (cred, newport, newport_type,
+ uids, nuids, gids, ngids);
+}
+
+error_t
+treefs_S_io_seek (struct treefs_protid *cred,
+ off_t offset, int whence, off_t *new_offset)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+ return treefs_s_io_seek (cred, offset, whence, new_offset);
+}
+
+error_t
+treefs_S_io_select (struct treefs_protid *cred, int *type, int *tag)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+ return treefs_s_io_select (cred, type, tag);
+}
+
+error_t
+treefs_S_io_sigio (struct treefs_protid *cred)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+ return treefs_s_io_sigio (cred);
+}
+
+error_t
+treefs_S_io_stat (struct treefs_protid *cred, io_statbuf_t *statbuf)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+ return treefs_s_io_statbuf_t (cred, statbuf);
+}
+
+error_t
+treefs_S_io_readsleep (struct treefs_protid *cred)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+ return treefs_s_io_readsleep (cred);
+}
+
+error_t
+treefs_S_io_eofnotify (struct treefs_protid *cred)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+ return treefs_s_io_eofnotify (cred);
+}
+
+error_t
+treefs_S_io_postnotify (struct treefs_protid *cred,
+ vm_offset_t start, vm_offset_t end)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+ return treefs_s_io_postnotify (cred, start, end);
+}
+
+error_t
+treefs_S_io_readnotify (struct treefs_protid *cred)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+ return treefs_s_io_readnotify (cred);
+}
+
+error_t
+treefs_S_io_server_version (struct treefs_protid *cred,
+ char *server_name,
+ int *major, int *minor, int *edit)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+ return treefs_s_io_server_version (cred, server_version, major, minor, edit);
+}
+
+error_t
+treefs_S_io_write (struct treefs_protid *cred,
+ char *data, mach_msg_type_number_t data_len,
+ off_t offset, mach_msg_type_number_t *amount)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+ return treefs_s_io_write (cred, data, data_len, offset, amount);
+}
diff --git a/libtreefs/trans-help.c b/libtreefs/trans-help.c
new file mode 100644
index 00000000..b28e93e1
--- /dev/null
+++ b/libtreefs/trans-help.c
@@ -0,0 +1,129 @@
+/* Helper routines for dealing with translators
+
+ Copyright (C) 1995 Free Software Foundation, Inc.
+
+ Written by Miles Bader <miles@gnu.ai.mit.edu>
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "trivfs.h"
+
+/* Return the active translator control port for NODE. If there is no
+ translator, active or passive, MACH_PORT_NULL is returned in CONTROL_PORT.
+ If there is a translator, it is started if necessary, and returned in
+ CONTROL_PORT. *DIR_PORT should be a port right to use as the new
+ translators parent directory. If it is MACH_PORT_NULL, a port is created
+ from DIR and PARENT_PORT and stored in *DIR_PORT; otherwise DIR and
+ PARENT_PORT are not used. Neither NODE or DIR should be locked when
+ calling this function. */
+error_t
+treefs_node_get_active_trans (struct treefs_node *node,
+ struct treefs_node *dir,
+ mach_port_t parent_port,
+ mach_port_t *control_port,
+ mach_port_t *dir_port)
+{
+ /* Fill in dir_port */
+ void make_dir_port ()
+ {
+ mutex_lock (&dir->lock);
+ *dir_port = treefs_node_make_right (dir, 0, parent_port, 0);
+ mach_port_insert_right (mach_task_self (),
+ *dir_port, *dir_port, MACH_MSG_TYPE_MAKE_SEND);
+ mutex_unlock (&dir->lock);
+ }
+
+ mutex_lock (&node->active_trans.lock);
+
+ if (node->active_trans.control != MACH_PORT_NULL)
+ {
+ mach_port_t control = node->active_trans.control;
+ mach_port_mod_refs (mach_task_self (), control,
+ MACH_PORT_RIGHT_SEND, 1);
+ mutex_unlock (&node->active_trans.lock);
+
+ /* Now we have a copy of the translator port that isn't
+ dependent on the translator lock itself. Relock
+ the directory, make a port from it, and then call
+ fsys_getroot. */
+
+ if (*dir_port == MACH_PORT_NULL)
+ make_dir_port ();
+
+ *control_port = control;
+
+ return 0;
+ }
+
+ mutex_unlock (&node->active_trans.lock);
+
+ /* If we get here, then we have no active control port.
+ Check to see if there is a passive translator, and if so
+ repeat the translator check. */
+ mutex_lock (&node->lock);
+ if (!node->istranslated)
+ {
+ *control_port = MACH_PORT_NULL;
+ return 0;
+ }
+
+ err = treefs_node_get_translator (node, trans, &trans_len);
+ if (err == E2BIG)
+ {
+ trans = alloca (trans_len);
+ err = treefs_node_get_translator (node, trans, &trans_len);
+ }
+ if (err)
+ {
+ mutex_unlock (&node->lock);
+ return err;
+ }
+
+ if (*dir_port == MACH_PORT_NULL)
+ {
+ mutex_unlock (&node->lock);
+ make_dir_port ();
+ mutex_lock (&node->lock);
+ }
+
+ /* Try starting the translator (this unlocks NODE). */
+ err = treefs_start_translator (node, trans, trans_len, *dir_port);
+ if (err)
+ return err;
+
+ /* Try again now that we've started the translator... This call
+ should be tail recursive. */
+ return
+ treefs_node_get_active_trans (node, dir, parent_port,
+ control_port, dir_port);
+}
+
+/* Drop the active translator CONTROL_PORT on NODE, unless it's no longer the
+ current active translator, in which case just drop a reference to it. */
+void
+treefs_node_drop_active_trans (struct treefs_node *node,
+ mach_port_t control_port)
+{
+ mutex_lock (&node->active_trans.lock);
+ /* Only zero the control port if it hasn't changed. */
+ if (node->active_trans.control == control)
+ fshelp_translator_drop (&node->active_trans);
+ mutex_unlock (&node->active_trans.lock);
+
+ /* And we're done with this port. */
+ mach_port_deallocate (mach_task_self (), control_port);
+}
diff --git a/libtreefs/trans-start.c b/libtreefs/trans-start.c
new file mode 100644
index 00000000..1b0156bf
--- /dev/null
+++ b/libtreefs/trans-start.c
@@ -0,0 +1,65 @@
+/* Starting a passive translator
+
+ Copyright (C) 1994, 1995 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "treefs.h"
+
+#include <fcntl.h>
+
+int fshelp_transboot_port_type = PT_TRANSBOOT;
+
+/* Start the translator TRANS (of length TRANS_LEN) on NODE, which should be
+ locked, and will be unlocked when this function returns. PARENT_PORT is
+ a send right to use as the parent port passed to the translator. */
+error_t
+_treefs_node_start_translator (struct treefs_node *node,
+ char *trans, unsigned trans_len,
+ file_t parent_port)
+{
+ error_t err;
+ int mode = O_READ | O_EXEC;
+ struct treefs_auth *auth;
+ file_t node_port;
+ uid_t uid, gid;
+
+ err = treefs_node_get_trans_auth (node, &auth);
+ if (err)
+ return err;
+
+ if (!node->fsys->readonly && treefs_node_type (node) == S_IFREG)
+ mode |= O_WRITE;
+
+ /* Create the REALNODE port for the new filesystem. */
+ node_port = treefs_node_make_right (node, mode, parent_port, auth);
+ mach_port_insert_right (mach_task_self (), node_port, node_port,
+ MACH_MSG_TYPE_MAKE_SEND);
+
+
+ mutex_unlock (&node->lock);
+
+ /* XXXX Change libfshelp so that it take more than 1 uid/gid? */
+ uid = auth->nuids > 0 ? auth->uids[0] : -1;
+ gid = auth->ngids > 0 ? auth->gids[0] : -1;
+
+ err =
+ fshelp_start_translator (&node->active_trans, trans, trans_len,
+ parent_port, node_port, uid, gid);
+
+ treefs_node_auth_unref (node, auth);
+
+ return err;
+}
diff --git a/libtreefs/treefs-hooks.h b/libtreefs/treefs-hooks.h
new file mode 100644
index 00000000..3af4a546
--- /dev/null
+++ b/libtreefs/treefs-hooks.h
@@ -0,0 +1,401 @@
+/* Hooks in libtreefs (also see "treefs-s-hooks.h")
+
+ Copyright (C) 1995 Free Software Foundation, Inc.
+
+ Written by Miles Bader <miles@gnu.ai.mit.edu>
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifndef __TREEFS_HOOKS_H__
+#define __TREEFS_HOOKS_H__
+
+#include "treefs.h"
+
+/* ---------------------------------------------------------------- */
+
+/* Hook indices */
+enum
+{
+ /* file rpcs */
+ TREEFS_HOOK_S_FILE_EXEC, TREEFS_HOOK_S_FILE_CHOWN,
+ TREEFS_HOOK_S_FILE_CHAUTHOR, TREEFS_HOOK_S_FILE_CHMOD,
+ TREEFS_HOOK_S_FILE_CHFLAGS, TREEFS_HOOK_S_FILE_UTIMES,
+ TREEFS_HOOK_S_FILE_SET_SIZE, TREEFS_HOOK_S_FILE_LOCK,
+ TREEFS_HOOK_S_FILE_LOCK_STAT, TREEFS_HOOK_S_FILE_ACCESS,
+ TREEFS_HOOK_S_FILE_NOTICE, TREEFS_HOOK_S_FILE_SYNC,
+ TREEFS_HOOK_S_FILE_GET_LINK_NODE,
+
+ /* io rpcs */
+ TREEFS_HOOK_S_IO_WRITE, TREEFS_HOOK_S_IO_READ, TREEFS_HOOK_S_IO_SEEK,
+ TREEFS_HOOK_S_IO_READABLE, TREEFS_HOOK_S_IO_SET_ALL_OPENMODES,
+ TREEFS_HOOK_S_IO_GET_OPENMODES, TREEFS_HOOK_S_IO_SET_SOME_OPENMODES,
+ TREEFS_HOOK_S_IO_CLEAR_SOME_OPENMODES, TREEFS_HOOK_S_IO_ASYNC,
+ TREEFS_HOOK_S_IO_MOD_OWNER, TREEFS_HOOK_S_IO_GET_OWNER,
+ TREEFS_HOOK_S_IO_GET_ICKY_ASYNC_ID, TREEFS_HOOK_S_IO_SELECT,
+ TREEFS_HOOK_S_IO_STAT, TREEFS_HOOK_S_IO_REAUTHENTICATE,
+ TREEFS_HOOK_S_IO_RESTRICT_AUTH, TREEFS_HOOK_S_IO_DUPLICATE,
+ TREEFS_HOOK_S_IO_SERVER_VERSION, TREEFS_HOOK_S_IO_MAP,
+ TREEFS_HOOK_S_IO_MAP_CNTL, TREEFS_HOOK_S_IO_RELEASE_CONCH,
+ TREEFS_HOOK_S_IO_EOFNOTIFY, TREEFS_HOOK_S_IO_PRENOTIFY,
+ TREEFS_HOOK_S_IO_POSTNOTIFY, TREEFS_HOOK_S_IO_READNOTIFY,
+ TREEFS_HOOK_S_IO_READSLEEP, TREEFS_HOOK_S_IO_SIGIO,
+
+ /* directory rpcs */
+ TREEFS_HOOK_S_DIR_LOOKUP, TREEFS_HOOK_S_DIR_READDIR, TREEFS_HOOK_S_DIR_MKDIR,
+ TREEFS_HOOK_S_DIR_RMDIR, TREEFS_HOOK_S_DIR_UNLINK, TREEFS_HOOK_S_DIR_LINK,
+ TREEFS_HOOK_S_DIR_RENAME, TREEFS_HOOK_S_DIR_MKFILE,
+ TREEFS_HOOK_S_DIR_NOTICE_CHANGES,
+
+ /* filesystem rpcs */
+ TREEFS_HOOK_S_FSYS_GETROOT, TREEFS_HOOK_S_FSYS_SET_OPTIONS,
+ TREEFS_HOOK_S_FSYS_SYNCFS, TREEFS_HOOK_S_FSYS_GETFILE, TREEFS_S_FSYS_GOAWAY,
+
+ /* Non-rpc fsys hooks */
+ TREEFS_HOOK_FSYS_CREATE_NODE, TREEFS_HOOK_FSYS_DESTROY_NODE,
+ TREEFS_HOOK_FSYS_GET_ROOT,
+
+ /* Node hooks */
+ TREEFS_HOOK_NODE_TYPE,
+ TREEFS_HOOK_NODE_UNLINKED, TREEFS_HOOK_NODE_MOD_LINK_COUNT,
+ TREEFS_HOOK_DIR_LOOKUP, TREEFS_HOOK_DIR_NOENT,
+ TREEFS_HOOK_DIR_CREATE_CHILD, TREEFS_HOOK_DIR_LINK, TREEFS_HOOK_DIR_UNLINK,
+ TREEFS_HOOK_NODE_OWNED, TREEFS_HOOK_NODE_ACCESS,
+ TREEFS_HOOK_NODE_GET_SYMLINK, TREEFS_HOOK_NODE_GET_PASSIVE_TRANS,
+ TREEFS_HOOK_NODE_START_TRANSLATOR, TREEFS_HOOK_NODE_GET_TRANS_AUTH,
+ TREEFS_HOOK_NODE_DROP, TREEFS_HOOK_NODE_INIT, TREEFS_HOOK_DIR_INIT,
+ TREEFS_HOOK_NODE_INIT_PEROPEN, TREEFS_HOOK_NODE_INIT_HANDLE,
+ TREEFS_HOOK_NODE_FINALIZE, TREEFS_HOOK_DIR_FINALIZE,
+ TREEFS_HOOK_NODE_FINALIZE_PEROPEN, TREEFS_HOOK_NODE_FINALIZE_HANDLE,
+
+ /* Reference counting support */
+ TREEFS_HOOK_NODE_NEW_REFS, TREEFS_HOOK_NODE_LOST_REFS,
+ TREEFS_HOOK_NODE_TRY_DROPPING_WEAK_REFS,
+
+ TREEFS_NUM_HOOKS
+};
+
+/* ---------------------------------------------------------------- */
+/* Hook calling/defining macros */
+
+/* Call the hook number HOOK in the hook vector HOOKS, whose function is of
+ type TYPE, with the args ARGS (my this is a useful comment). */
+#define TREEFS_CALL_HOOK(hooks, hook, type, args...) \
+ ((type *)(hooks)[hook])(args)
+#define TREEFS_CALL_HANDLE_HOOK(h, hook, type, args...) \
+ ({struct treefs_handle *_tfs_cn_h = (h); \
+ TREEFS_CALL_HOOK(_tfs_cn_h->po->node->hooks,hook,type, \
+ _tfs_cn_h , ##args);})
+#define TREEFS_CALL_NODE_HOOK(node, hook, type, args...) \
+ ({struct treefs_node *_tfs_cn_node = (node); \
+ TREEFS_CALL_HOOK(_tfs_cn_node->hooks,hook,type, _tfs_cn_node , ##args);})
+#define TREEFS_CALL_FSYS_HOOK(fsys, hook, type, args...) \
+ ({struct treefs_fsys *_tfs_cn_fsys = (fsys); \
+ TREEFS_CALL_HOOK(_tfs_cn_fsys->hooks,hook,type, _tfs_cn_fsys , ##args);})
+
+/* Shorthand form of TREEFS_CALL_*_HOOK (only used here). */
+#define _TREEFS_CHH(h, hook_id, type_id, args...) \
+ TREEFS_CALL_HANDLE_HOOK(h, TREEFS_HOOK_##hook_id, treefs_##type_id##_t , ##args)
+#define _TREEFS_CNH(node, hook_id, type_id, args...) \
+ TREEFS_CALL_NODE_HOOK(node, TREEFS_HOOK_##hook_id, treefs_##type_id##_t , ##args)
+#define _TREEFS_CFH(fsys, hook_id, type_id, args...) \
+ TREEFS_CALL_FSYS_HOOK(fsys, TREEFS_HOOK_##hook_id, treefs_##type_id##_t , ##args)
+
+/* Forward declare some structures used before definition. */
+struct treefs_node;
+struct treefs_fsys;
+struct treefs_auth;
+struct treefs_handle;
+struct treefs_peropen;
+
+/* Shorthand for declaring the various hook types (each hook has an
+ associated type so that a user can type-check his hook routine). */
+#define DNH(name_sym, ret_type, argtypes...) \
+ typedef ret_type treefs_##name_sym##_t (struct treefs_node * , ##argtypes);
+#define DFH(name_sym, ret_type, argtypes...) \
+ typedef ret_type treefs_##name_sym##_t (struct treefs_fsys * , ##argtypes);
+
+/* ---------------------------------------------------------------- */
+/* Non RPC hooks */
+
+/* Called to get the root node of the a filesystem, with a reference,
+ returning it in ROOT, or return an error if it can't be had. The default
+ hook just returns FSYS->root or an error if it's NULL. Note that despite
+ the similar name, this is very different from fsys_s_getroot! FSYS must
+ not be locked. */
+DFH(fsys_get_root, error_t, struct treefs_node **root)
+#define treefs_fsys_get_root(fsys, args...) \
+ _TREEFS_CFH(fsys, FSYS_GET_ROOT, fsys_get_root , ##args)
+
+/* Called on a filesystem to create a new node in that filesystem, returning
+ it, with one reference, in NODE. DIR, if non-NULL, is the nominal parent
+ directory, and MODE and AUTH are the desired mode and user info
+ respectively. This hook should also call node_init_stat & node_init to
+ initialize the various user bits. */
+DFH(fsys_create_node, error_t,
+ struct treefs_node *dir, mode_t mode, struct treefs_auth *auth,
+ struct treefs_node **node)
+#define treefs_fsys_create_node(fsys, args...) \
+ _TREEFS_CFH(fsys, FSYS_CREATE_NODE, fsys_create_node , ##args)
+
+/* Called on a filesystem to destroy a node in that filesystem. This call
+ should *really* destroy it -- i.e., it's only called once all references
+ are gone. */
+DFH(fsys_destroy_node, void, struct treefs_node *node)
+#define treefs_fsys_destroy_node(fsys, node) \
+ _TREEFS_CFH(fsys, FSYS_DESTROY_NODE, fsys_destroy_node , ##args)
+
+/* Returns the type of NODE, as an S_IFMT value (e.g., S_IFDIR). The
+ default routine just looks at NODE's stat mode. */
+DNH(node_type, int);
+#define treefs_node_type(node, args...) \
+ _TREEFS_CNH(node, NODE_TYPE, node_type , ##args)
+
+#define treefs_node_isdir(node) (treefs_node_type(node) == S_IFDIR)
+#define treefs_node_isreg(node) (treefs_node_type(node) == S_IFREG)
+
+/* Return TRUE if NODE is `unlinked' -- that is, can be deleted when all
+ (in-memory) references go away. */
+DNH(node_unlinked, int);
+#define treefs_node_unlinked(node, args...) \
+ _TREEFS_CNH(node, NODE_UNLINKED, node_unlinked , ##args)
+
+/* Changes the link count of NODE by CHANGE; if any error is returned, the
+ operation trying to change the link count will fail, so filesystems that
+ don't support real links can restrict it to 1 or 0. This is mostly used
+ by the in-core directory code when it makes a link. The default hook uses
+ the link field of NODE's stat entry. */
+DNH(node_mod_link_count, error_t, int change);
+#define treefs_node_mod_link_count(node, args...) \
+ _TREEFS_CNH(node, NODE_MOD_LINK_COUNT, node_mod_link_count , ##args)
+
+/* Lookup NAME in NODE, returning the result in CHILD; AUTH should be used to
+ do authentication. If FLAGS contains O_CREAT, and NAME is not found, then
+ an entry should be created with a mode of CREATE_MODE (which includes the
+ S_IFMT bits, e.g., S_IFREG means a normal file), unless O_EXCL is also
+ set, in which case EEXIST should be returned. Possible special errors
+ returned include: EAGAIN -- result would be the parent of our filesystem
+ root. Note that is a single-level lookup, unlike treefs_s_dir_lookup. */
+DNH(dir_lookup, error_t,
+ char *name, struct treefs_auth *auth, int flags, int create_mode,
+ struct treefs_node **child)
+#define treefs_dir_lookup(dir, args...) \
+ _TREEFS_CNH(dir, DIR_LOOKUP, dir_lookup , ##args)
+
+/* Called by the default implementation of treefs_dir_lookup (and possibly
+ user-versions as well) when a directory lookup returns ENOENT, before a
+ new node is created. This hook may return the desire node in CHILD and
+ return 0, or return an error code. Note that a returned node need not
+ actually be in the directory DIR, and indeed may be anonymous. */
+DNH(dir_noent, error_t,
+ char *name, struct treefs_auth *auth, int flags, int create_mode,
+ struct treefs_node **child);
+#define treefs_dir_noent(dir, args...) \
+ _TREEFS_CNH(dir, DIR_NOENT, dir_noent , ##args)
+
+/* Return in CHILD a new node with one reference, presumably a possible child
+ of DIR, with a mode MODE. All attempts to create a new node go through
+ this hook, so it may be overridden to easily control creation (e.g.,
+ replacing it with a hook that always returns EPERM). Note that this
+ routine doesn't actually enter the child into the directory, or give the
+ node a non-zero link count, that should be done by the caller. */
+DNH(dir_create_child, error_t,
+ mode_t mode, struct treefs_auth *auth, struct treefs_node **child);
+#define treefs_dir_create_child(dir, args...) \
+ _TREEFS_CNH(dir, DIR_CREATE_CHILD, dir_create_child , ##args)
+
+/* Link the node CHILD into DIR as NAME, using AUTH to check authentication.
+ DIR should be locked and CHILD shouldn't be. The default hook puts it
+ into DIR's in-core directory, and uses a reference to CHILD (this way, a
+ node can be linked to both in-core and out-of-core directories and the
+ permanent link-count will be right). */
+DNH(dir_link, error_t,
+ char *name, struct treefs_node *child, struct treefs_auth *auth)
+#define treefs_dir_link(dir, args...) \
+ _TREEFS_CNH(dir, DIR_LINK, dir_link , ##args)
+
+/* Remove the entry NAME from DIR, using AUTH to check authentication. DIR
+ should be locked. The default hook removes NAME from DIR's in-core
+ directory. */
+DNH(dir_unlink, error_t, char *name, struct treefs_auth *auth)
+#define treefs_dir_unlink(dir, args...) \
+ _TREEFS_CNH(dir, DIR_UNLINK, dir_unlink , ##args)
+
+/* Check to see if the user identified by AUTH is permitted to do owner-only
+ operations on node NP; if so, return 0; if not, return EPERM. */
+DNH(node_owned, error_t, struct treefs_auth *auth)
+#define treefs_node_owned(node, args...) \
+ _TREEFS_CNH(node, NODE_OWNED, node_owned , ##args)
+
+/* Check to see is the user identified by AUTH is permitted to do
+ operation OP on node NP. Op is one of S_IREAD, S_IWRITE, or S_IEXEC.
+ Return 0 if the operation is permitted and EACCES if not. */
+DNH(node_access, error_t, int opt, struct treefs_auth *auth)
+#define treefs_node_access(node, args...) \
+ _TREEFS_CNH(node, NODE_ACCESS, node_access , ##args)
+
+/* NODE now has no more references; clean all state. The
+ _treefs_node_refcnt_lock must be held, and will be released upon return.
+ NODE must be locked. */
+DNH(node_drop, error_t);
+#define treefs_node_drop(node, args...) \
+ _TREEFS_CNH(node, NODE_DROP, node_drop , ##args)
+
+/* Called when a new directory is created, after trees_node_init. If this
+ routine returns an error, the new node will be destroyed and the create
+ will fail. */
+DNH(dir_init, error_t)
+#define treefs_dir_init(dir, args...) \
+ _TREEFS_CNH(dir, DIR_INIT, dir_init , ##args)
+
+/* If NODE is a symlink, copies the contents into BUF, which should have at
+ least *LEN bytes available, and returns 0; if the symlink is too big,
+ E2BIG is returned. Either way, the actual length of the symlink is
+ returned in *LEN (so if it's too big, you can allocate an appropiately
+ sized buffer and try again). If NODE is not a symlink, EINVAL is
+ returned. */
+DNH(node_get_symlink, error_t, char *buf, int *len)
+#define treefs_node_get_symlink(node, args...) \
+ _TREEFS_CNH(node, NODE_GET_SYMLINK, node_get_symlink , ##args)
+
+/* If NODE has a passive translator, copies the contents into BUF, which
+ should have at least *LEN bytes available, and returns 0; if the string is
+ too big, E2BIG is returned. Either way, the actual length of the
+ translator string is returned in *LEN (so if it's too big, you can
+ allocate an appropiately sized buffer and try again). If NODE has no
+ passive translator, EINVAL is returned. */
+DNH(node_get_passive_trans, error_t, char *buf, int *len)
+#define treefs_node_get_passive_trans(node, args...) \
+ _TREEFS_CNH(node, NODE_GET_PASSIVE_TRANS, node_get_passive_trans , ##args)
+
+/* Returns the user and group that a newly started translator should be
+ authenticated as. The default just returns the owner/group of NODE. */
+DNH(node_get_trans_auth, error_t, uid_t *uid, gid_t *gid)
+#define treefs_node_get_trans_auth(node, args...) \
+ _TREEFS_CNH(node, NODE_GET_TRANS_AUTH, node_get_trans_auth , ##args)
+
+/* Start the translator TRANS (of length TRANS_LEN) on NODE, which should be
+ locked, and will be unlocked during the execution of this function.
+ PARENT_PORT should be a send right to use as the parent port passed to the
+ translator. */
+DNH(node_start_translator, error_t,
+ char *trans, unsigned trans_len, file_t parent_port)
+#define treefs_node_start_translator(node, args...) \
+ _TREEFS_CNH(node, NODE_START_TRANSLATOR, node_start_translator , ##args)
+
+/* Called to initialize a new node's stat entry, after all default fields are
+ filled in (but before node_init is called). */
+DNH(node_init_stat, error_t,
+ struct treefs_node *dir, mode_t mode, struct treefs_auth *auth)
+#define treefs_node_init_stat(node, args...) \
+ _TREEFS_CNH(node, NODE_INIT_STAT, node_init_stat , ##args)
+
+/* Called to initialize a new node, after all default fields are filled in.
+ If this routine returns an error, the new node will be destroyed and the
+ create will fail. */
+DNH(node_init, error_t,
+ struct treefs_node *dir, mode_t mode, struct treefs_auth *auth)
+#define treefs_node_init(node, args...) \
+ _TREEFS_CNH(node, NODE_INIT, node_init , ##args)
+
+/* Called to cleanup node-specific info in a node about to be destroyed. */
+DNH(node_finalize, void)
+#define treefs_node_finalize(node, args...) \
+ _TREEFS_CNH(node, NODE_FINALIZE, node_finalize , ##args)
+
+/* Called to cleanup node-specific directory info in a node about to be
+ destroyed. Called before node_finalize. */
+DNH(dir_finalize, void)
+#define treefs_dir_finalize(dir, args...) \
+ _TREEFS_CNH(dir, DIR_FINALIZE, dir_finalize , ##args)
+
+/* Called when the new peropen structure PO is made for NODE, with the
+ authorization in AUTH, opened with the flags FLAGS (note that this a copy
+ of PO->flags, which the hook may modify). If an error is returned, the
+ open will fail with that error. The default hook does explicit checks
+ against AUTH using treefs_node_access, and otherwise does nothing. */
+DNH(node_init_peropen, error_t,
+ struct treefs_peropen *po, int flags, struct treefs_auth *auth)
+#define treefs_node_init_peropen(node, args...) \
+ _TREEFS_CNH(node, NODE_INIT_PEROPEN, node_init_peropen , ##args)
+
+/* Called the peropen structure PO for NODE is being destroyed. */
+DNH(node_finalize_peropen, void, struct treefs_peropen *po)
+#define treefs_node_finalize_peropen(node, args...) \
+ _TREEFS_CNH(node, NODE_FINALIZE_PEROPEN, node_finalize_peropen , ##args)
+
+/* Called when a new handle structure is made for a node. The default does
+ nothing. */
+DNH(node_init_handle, void, struct treefs_handle *handle)
+#define treefs_node_init_handle(node, args...) \
+ _TREEFS_CNH(node, NODE_INIT_HANDLE, node_init_handle , ##args)
+
+/* Called when the handle HANDLE for NODE is being destroyed. */
+DNH(node_finalize_handle, void, struct treefs_handle *handle)
+#define treefs_node_finalize_handle(node, args...) \
+ _TREEFS_CNH(node, NODE_FINALIZE_HANDLE, node_finalize_handle , ##args)
+
+/* ---------------------------------------------------------------- */
+/* Ref counting stuff */
+
+/* NODE has just acquired a hard reference where it had none previously. It
+ is thus now OK again to have weak references without real users. NODE is
+ locked. */
+DNH(node_new_refs, void);
+#define treefs_node_new_refs(node, args...) \
+ _TREEFS_CNH(node, NODE_NEW_REFS, node_new_refs , ##args)
+
+/* NODE has some weak references but has just lost its last hard reference.
+ NP is locked. */
+DNH(node_lost_refs, void);
+#define treefs_node_lost_refs(node, args...) \
+ _TREEFS_CNH(node, NODE_LOST_REFS, node_lost_refs , ##args)
+
+/* NODE has some weak references, but has just lost its last hard references.
+ Take steps so that if any weak references can be freed, they are. NP is
+ locked as is the pager refcount lock. This function will be called after
+ treefs_node_lost_refs. */
+DNH(node_try_dropping_weak_refs, void);
+#define treefs_node_try_dropping_weak_refs(node, args...) \
+ _TREEFS_CNH(node, NODE_TRY_DROPPING_WEAK_REFS, node_try_dropping_weak_refs , ##args)
+
+/* Turn off our shorthand notation. */
+#undef DNH
+#undef DFH
+
+/* ---------------------------------------------------------------- */
+/* Default routines for some hooks (each is the default value for the hook
+ with the same name minus the leading underscore). When you add something
+ here, you should also add it to the initialize code in defhooks.c. */
+
+treefs_fsys_create_node_t _treefs_fsys_create_node;
+treefs_fsys_destroy_node_t _treefs_fsys_destroy_node;
+treefs_fsys_get_root_t _treefs_fsys_get_root;
+treefs_node_type_t _treefs_node_type;
+treefs_node_unlinked_t _treefs_node_unlinked;
+treefs_node_mod_link_count_t _treefs_node_mod_link_count;
+treefs_node_mod_link_count_t _treefs_mod_link_count;
+treefs_dir_lookup_t _treefs_dir_lookup;
+treefs_dir_noent_t _treefs_dir_noent;
+treefs_dir_create_child_t _treefs_dir_create_child;
+treefs_dir_link_t _treefs_dir_link;
+treefs_dir_unlink_t _treefs_dir_unlink;
+treefs_node_owned_t _treefs_node_owned;
+treefs_node_access_t _treefs_node_access;
+treefs_node_start_translator_t _treefs_node_start_translator;
+treefs_node_get_trans_auth_t _treefs_node_get_trans_auth;
+
+#endif /* __TREEFS_HOOKS_H__ */
diff --git a/libtreefs/treefs-s-hooks.h b/libtreefs/treefs-s-hooks.h
new file mode 100644
index 00000000..2ea9e7ab
--- /dev/null
+++ b/libtreefs/treefs-s-hooks.h
@@ -0,0 +1,231 @@
+/* RPC server hooks in libtreefs (also see "treefs-hooks.h")
+
+ Copyright (C) 1995 Free Software Foundation, Inc.
+
+ Written by Miles Bader <miles@gnu.ai.mit.edu>
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifndef __TREEFS_S_HOOKS_H__
+#define __TREEFS_S_HOOKS_H__
+
+#include "treefs-hooks.h"
+
+/* Shorthand for declaring the various hook types (each hook has an
+ associated type so that a user can type-check his hook routine). */
+#define DHH(name_sym, ret_type, argtypes...) \
+ typedef ret_type treefs_##name_sym##_t (struct treefs_handle * , ##argtypes);
+#define DFH(name_sym, ret_type, argtypes...) \
+ typedef ret_type treefs_##name_sym##_t (struct treefs_fsys * , ##argtypes);
+
+/* ---------------------------------------------------------------- */
+/* Hooks for file RPCs. See <hurd/fs.defs> for more info. */
+
+DHH(s_file_exec, error_t,
+ task_t, int, char *, unsigned, char *, unsigned, mach_port_t *, unsigned,
+ mach_port_t *, unsigned, int *, unsigned,
+ mach_port_t *, unsigned, mach_port_t *, unsigned)
+#define treefs_s_file_exec(h, args...) \
+ _TREEFS_CHH(h, S_FILE_EXEC, s_file_exec , ##args)
+DHH(s_file_chown, error_t, uid_t, gid_t)
+#define treefs_s_file_chown(h, args...) \
+ _TREEFS_CHH(h, S_FILE_CHOWN, s_file_chown , ##args)
+DHH(s_file_chauthor, error_t, uid_t)
+#define treefs_s_file_chauthor(h, args...) \
+ _TREEFS_CHH(h, S_FILE_CHAUTHOR, s_file_chauthor , ##args)
+DHH(s_file_chmod, error_t, mode_t)
+#define treefs_s_file_chmod(h, args...) \
+ _TREEFS_CHH(h, S_FILE_CHMOD, s_file_chmod , ##args)
+DHH(s_file_chflags, error_t, int)
+#define treefs_s_file_chflags(h, args...) \
+ _TREEFS_CHH(h, S_FILE_CHFLAGS, s_file_chflags , ##args)
+DHH(s_file_utimes, error_t, time_value_t, time_value_t)
+#define treefs_s_file_utimes(h, args...) \
+ _TREEFS_CHH(h, S_FILE_UTIMES, s_file_utimes , ##args)
+DHH(s_file_truncate, error_t, off_t)
+#define treefs_s_file_truncate(h, args...) \
+ _TREEFS_CHH(h, S_FILE_TRUNCATE, s_file_truncate , ##args)
+DHH(s_file_lock, error_t, struct treefs_handle *, int)
+#define treefs_s_file_lock(h, args...) \
+ _TREEFS_CHH(h, S_FILE_LOCK, s_file_lock , ##args)
+DHH(s_file_lock_stat, error_t, int *, int *)
+#define treefs_s_file_lock_stat(h, args...) \
+ _TREEFS_CHH(h, S_FILE_LOCK_STAT, s_file_lock_stat , ##args)
+DHH(s_file_notice_changes, error_t, mach_port_t)
+#define treefs_s_file_notice_changes(h, args...) \
+ _TREEFS_CHH(h, S_FILE_NOTICE, s_file_notice_changes , ##args)
+DHH(s_file_sync, error_t, int)
+#define treefs_s_file_sync(h, args...) \
+ _TREEFS_CHH(h, S_FILE_SYNC, s_file_sync , ##args)
+DHH(s_file_getlinknode, error_t, file_t *, mach_msg_type_name_t *)
+#define treefs_s_file_getlinknode(h, args...) \
+ _TREEFS_CHH(h, S_FILE_GET_LINK_NODE, s_file_getlinknode , ##args)
+
+/* ---------------------------------------------------------------- */
+/* Hooks for IO rpcs. See <hurd/io.defs> for more info. */
+
+DHH(s_io_write, error_t, char *, unsigned, off_t, int *)
+#define treefs_s_io_write(h, args...) \
+ _TREEFS_CHH(h, S_IO_WRITE, s_io_write , ##args)
+DHH(s_io_read, error_t, char **, unsigned *, off_t, int)
+#define treefs_s_io_read(h, args...) \
+ _TREEFS_CHH(h, S_IO_READ, s_io_read , ##args)
+DHH(s_io_seek, error_t, off_t, int, off_t *)
+#define treefs_s_io_seek(h, args...) \
+ _TREEFS_CHH(h, S_IO_SEEK, s_io_seek , ##args)
+DHH(s_io_readable, error_t, unsigned *)
+#define treefs_s_io_readable(h, args...) \
+ _TREEFS_CHH(h, S_IO_READABLE, s_io_readable , ##args)
+DHH(s_io_set_all_openmodes, error_t, int)
+#define treefs_s_io_set_all_openmodes(h, args...) \
+ _TREEFS_CHH(h, S_IO_SET_ALL_OPENMODES, s_io_set_all_openmodes , ##args)
+DHH(s_io_get_openmodes, error_t, int *)
+#define treefs_s_io_get_openmodes(h, args...) \
+ _TREEFS_CHH(h, S_IO_GET_OPENMODES, s_io_get_openmodes , ##args)
+DHH(s_io_set_some_openmodes, error_t, int)
+#define treefs_s_io_set_some_openmodes(h, args...) \
+ _TREEFS_CHH(h, S_IO_SET_SOME_OPENMODES, s_io_set_some_openmodes , ##args)
+DHH(s_io_clear_some_openmodes, error_t, int)
+#define treefs_s_io_clear_some_openmodes(h, args...) \
+ _TREEFS_CHH(h, S_IO_CLEAR_SOME_OPENMODES, s_io_clear_some_openmodes , ##args)
+DHH(s_io_async, error_t, mach_port_t, mach_port_t *, mach_msg_type_name_t *)
+#define treefs_s_io_async(h, args...) \
+ _TREEFS_CHH(h, S_IO_ASYNC, s_io_async , ##args)
+DHH(s_io_mod_owner, error_t, pid_t)
+#define treefs_s_io_mod_owner(h, args...) \
+ _TREEFS_CHH(h, S_IO_MOD_OWNER, s_io_mod_owner , ##args)
+DHH(s_io_get_owner, error_t, pid_t *)
+#define treefs_s_io_get_owner(h, args...) \
+ _TREEFS_CHH(h, S_IO_GET_OWNER, s_io_get_owner , ##args)
+DHH(s_io_get_icky_async_id, error_t, mach_port_t *, mach_msg_type_name_t *)
+#define treefs_s_io_get_icky_async_id(h, args...) \
+ _TREEFS_CHH(h, S_IO_GET_ICKY_ASYNC_ID, s_io_get_icky_async_id , ##args)
+DHH(s_io_select, error_t, int *, int *)
+#define treefs_s_io_select(h, args...) \
+ _TREEFS_CHH(h, S_IO_SELECT, s_io_select , ##args)
+DHH(s_io_stat, error_t, io_statbuf_t *)
+#define treefs_s_io_stat(h, args...) \
+ _TREEFS_CHH(h, S_IO_STAT, s_io_stat , ##args)
+DHH(s_io_reauthenticate, error_t, mach_port_t *, mach_msg_type_name_t *)
+#define treefs_s_io_reauthenticate(h, args...) \
+ _TREEFS_CHH(h, S_IO_REAUTHENTICATE, s_io_reauthenticate , ##args)
+DHH(s_io_restrict_auth, error_t,
+ mach_port_t *, mach_msg_type_name_t *, uid_t *, int, gid_t *, int);
+#define treefs_s_io_restrict_auth(h, args...) \
+ _TREEFS_CHH(h, S_IO_RESTRICT_AUTH, s_io_restrict_auth , ##args)
+DHH(s_io_duplicate, error_t, mach_port_t *, mach_msg_type_name_t *)
+#define treefs_s_io_duplicate(h, args...) \
+ _TREEFS_CHH(h, S_IO_DUPLICATE, s_io_duplicate , ##args)
+DHH(s_io_server_version, error_t, char *, int *, int *, int *)
+#define treefs_s_io_server_version(h, args...) \
+ _TREEFS_CHH(h, S_IO_SERVER_VERSION, s_io_server_version , ##args)
+DHH(s_io_map, error_t, mach_port_t *, mach_msg_type_name_t *, mach_port_t *, mach_msg_type_name_t *)
+#define treefs_s_io_map(h, args...) \
+ _TREEFS_CHH(h, S_IO_MAP, s_io_map , ##args)
+DHH(s_io_map_cntl, error_t, mach_port_t *, mach_msg_type_name_t *)
+#define treefs_s_io_map_cntl(h, args...) \
+ _TREEFS_CHH(h, S_IO_MAP_CNTL, s_io_map_cntl , ##args)
+DHH(s_io_release_conch, error_t, struct treefs_handle *)
+#define treefs_s_io_release_conch(h, args...) \
+ _TREEFS_CHH(h, S_IO_RELEASE_CONCH, s_io_release_conch, ##args)
+DHH(s_io_eofnotify, error_t);
+#define treefs_s_io_eofnotify(h, args...) \
+ _TREEFS_CHH(h, S_IO_EOFNOTIFY, s_io_eofnotify , ##args)
+DHH(s_io_prenotify, error_t, vm_offset_t, vm_offset_t);
+#define treefs_s_io_prenotify(h, args...) \
+ _TREEFS_CHH(h, S_IO_PRENOTIFY, s_io_prenotify , ##args)
+DHH(s_io_postnotify, error_t, vm_offset_t, vm_offset_t);
+#define treefs_s_io_postnotify(h, args...) \
+ _TREEFS_CHH(h, S_IO_POSTNOTIFY, s_io_postnotify , ##args)
+DHH(s_io_readnotify, error_t);
+#define treefs_s_io_readnotify(h, args...) \
+ _TREEFS_CHH(h, S_IO_READNOTIFY, s_io_readnotify , ##args)
+DHH(s_io_readsleep, error_t);
+#define treefs_s_io_readsleep(h, args...) \
+ _TREEFS_CHH(h, S_IO_READSLEEP, s_io_readsleep , ##args)
+DHH(s_io_sigio, error_t);
+#define treefs_s_io_sigio(h, args...) \
+ _TREEFS_CHH(h, S_IO_SIGIO, s_io_sigio , ##args)
+
+/* ---------------------------------------------------------------- */
+/* Hooks for directory RPCs. See <hurd/fs.defs> for more info. */
+
+DHH(s_dir_lookup, error_t,
+ char *, int, mode_t, enum retry_type *, char *,
+ file_t *, mach_msg_type_name_t *);
+#define treefs_s_dir_lookup(h, args...) \
+ _TREEFS_CHH(h, S_DIR_LOOKUP, s_dir_lookup , ##args)
+DHH(s_dir_readdir, error_t, char **, unsigned, int, int, vm_size_t, int *);
+#define treefs_s_dir_readdir(h, args...) \
+ _TREEFS_CHH(h, S_DIR_READDIR, s_dir_readdir , ##args)
+DHH(s_dir_mkdir, error_t, char *, mode_t);
+#define treefs_s_dir_mkdir(h, args...) \
+ _TREEFS_CHH(h, S_DIR_MKDIR, s_dir_mkdir , ##args)
+DHH(s_dir_rmdir, error_t, char *);
+#define treefs_s_dir_rmdir(h, args...) \
+ _TREEFS_CHH(h, S_DIR_RMDIR, s_dir_rmdir , ##args)
+DHH(s_dir_unlink, error_t, char *);
+#define treefs_s_dir_unlink(h, args...) \
+ _TREEFS_CHH(h, S_DIR_UNLINK, s_dir_unlink , ##args)
+DHH(s_dir_link, error_t, file_t, char *);
+#define treefs_s_dir_link(h, args...) \
+ _TREEFS_CHH(h, S_DIR_LINK, s_dir_link , ##args)
+DHH(s_dir_rename, error_t, char *, file_t, char *);
+#define treefs_s_dir_rename(h, args...) \
+ _TREEFS_CHH(h, S_DIR_RENAME, s_dir_rename , ##args)
+DHH(s_dir_mkfile, error_t, int, mode_t, mach_port_t *, mach_msg_type_name_t *);
+#define treefs_s_dir_mkfile(h, args...) \
+ _TREEFS_CHH(h, S_DIR_MKFILE, s_dir_mkfile , ##args)
+DHH(s_dir_notice_changes, error_t, mach_port_t *, mach_msg_type_name_t *);
+#define treefs_s_dir_notice_changes(h, args...) \
+ _TREEFS_CHH(h, S_DIR_NOTICE_CHANGES, s_dir_notice_changes , ##args)
+
+/* ---------------------------------------------------------------- */
+/* fsys RPCs (called on the filesystem itself) */
+
+DFH(s_fsys_getroot, error_t,
+ mach_port_t, uid_t *, unsigned, gid_t *, unsigned, int,
+ retry_type *, char *, file_t *, mach_msg_type_name_t *)
+#define treefs_s_fsys_getroot(fsys, args...) \
+ _TREEFS_CFH(fsys, S_FSYS_GETROOT, s_fsys_getroot , ##args)
+DFH(s_fsys_set_options, error_t, char *, unsigned, int)
+#define treefs_s_fsys_set_options(fsys, args...) \
+ _TREEFS_CFH(fsys, S_FSYS_SET_OPTIONS, s_fsys_set_options , ##args)
+DFH(s_fsys_goaway, error_t, int)
+#define treefs_s_fsys_goaway(fsys, args...) \
+ _TREEFS_CFH(fsys, S_FSYS_GOAWAY, s_fsys_goaway , ##args)
+DFH(s_fsys_getfile, error_t,
+ uid_t *, unsigned, gid_t *, unsigned, char *, unsigned,
+ mach_port_t *, mach_msg_type_name_t *)
+#define treefs_s_fsys_getfile(fsys, args...) \
+ _TREEFS_CFH(fsys, S_FSYS_GETFILE, s_fsys_getfile , ##args)
+DFH(s_fsys_syncfs, error_t, int, int)
+#define treefs_s_fsys_syncfs(fsys, args...) \
+ _TREEFS_CFH(fsys, S_FSYS_SYNCFS, s_fsys_syncfs , ##args)
+
+/* Turn off our shorthand notation. */
+#undef DHH
+
+/* ---------------------------------------------------------------- */
+/* Default routines for some hooks (each is the default value for the hook
+ with the same name minus the leading underscore). When you add something
+ here, you should also add it to the initialize code in defhooks.c. */
+
+treefs_s_dir_lookup_t _treefs_s_dir_lookup;
+treefs_s_fsys_getroot_t _treefs_s_fsys_getroot;
+
+#endif /* __TREEFS_S_HOOKS_H__ */
diff --git a/libtreefs/treefs.h b/libtreefs/treefs.h
new file mode 100644
index 00000000..b0c26849
--- /dev/null
+++ b/libtreefs/treefs.h
@@ -0,0 +1,472 @@
+/* Hierarchial filesystem support
+
+ Copyright (C) 1995 Free Software Foundation, Inc.
+
+ Written by Miles Bader <miles@gnu.ai.mit.edu>
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifndef __TREEFS_H__
+#define __TREEFS_H__
+
+#include <errno.h>
+#include <cthreads.h>
+#include <assert.h>
+
+#include <sys/stat.h>
+
+#include <hurd/hurd_types.h>
+#include <hurd/ports.h>
+#include <hurd/fshelp.h>
+
+/* Include the hook calling macros and non-rpc hook definitions (to get
+ those, include "trees-s-hooks.h"). */
+#include "treefs-hooks.h"
+
+/* ---------------------------------------------------------------- */
+
+typedef void (**treefs_hook_vector_t)();
+
+/* A list of nodes. */
+struct treefs_node_list;
+
+/* Each user port referring to a file points to one of these. */
+struct treefs_handle
+{
+ struct port_info pi;
+ struct treefs_auth *auth; /* User identification */
+ struct treefs_peropen *po; /* The io object itself */
+ void *u; /* for user use */
+};
+
+/* An authentication cookie. */
+struct treefs_auth
+{
+ int refs;
+ uid_t *uids, *gids;
+ int nuids, ngids;
+ int isroot;
+ void *u; /* for user use */
+};
+
+/* Bits the user is permitted to set with io_*_openmodes */
+#define TREEFS_SETTABLE_FLAGS (O_APPEND|O_ASYNC|O_FSYNC|O_NONBLOCK|O_NOATIME)
+
+/* Bits that are turned off after open */
+#define TREEFS_OPENONLY_FLAGS (O_CREAT|O_EXCL|O_NOLINK|O_NOTRANS|O_NONBLOCK)
+
+struct treefs_peropen
+{
+ int refs;
+ int open_flags;
+ int user_lock_state;
+
+ /* A port to the directory through which this open file was reached. */
+ mach_port_t parent_port;
+
+ void *u; /* for user use */
+
+ struct treefs_node *node;
+};
+
+/* A filesystem node in the tree. */
+struct treefs_node
+{
+ struct stat stat;
+ struct treefs_fsys *fsys;
+
+ struct trans_link active_trans;
+ char *passive_trans;
+ struct lock_box user_lock;
+
+ struct mutex lock;
+ unsigned refs, weak_refs;
+
+ /* Node ops */
+ treefs_hook_vector_t hooks;
+
+ /* If this node is a directory, then this is the directory state. */
+ struct treefs_node_list *children;
+
+ void *u; /* for user use */
+};
+
+struct treefs_node_list
+{
+ struct treefs_node **nodes;
+ unsigned short num_nodes, nodes_alloced;
+ char *names;
+ unsigned short names_len, names_alloced;
+};
+
+struct treefs_fsys
+{
+ struct port_info pi;
+ struct mutex lock;
+
+ /* The root node in this filesystem. */
+ struct treefs_node *root;
+
+ /* The port for the node which this filesystem is translating. */
+ mach_port_t underlying_port;
+ /* And stat info for it. */
+ struct stat underlying_stat;
+
+ /* Flags from the TREEFS_FSYS_ set. */
+ int flags;
+ /* Max number of symlink expansions allowed. */
+ unsigned max_symlinks;
+ /* Sync interval (in seconds). 0 means all operations should be
+ synchronous, any negative value means never sync. */
+ int sync_interval;
+
+ /* Values to return from a statfs. */
+ int fs_type;
+ int fs_id;
+
+ /* This is the hook vector that each new node in this filesystem starts out
+ with. */
+ treefs_hook_vector_t hooks;
+
+ /* The port bucket to which all of our ports belongs. */
+ struct ports_bucket *port_bucket;
+
+ /* Various classes of ports we know about. */
+ struct port_class *handle_port_class;
+
+ void *u; /* for user use */
+};
+
+/* Filesystem flags. */
+#define TREEFS_FSYS_READONLY 0x1
+
+/* ---------------------------------------------------------------- */
+/* In-core directory management routines (`mdir' == `memory dir'). These are
+ intended for keeping non-permanent directory state. If called on a
+ non-dir, ENOTDIR is returned. */
+
+/* Add CHILD to DIR as NAME, replacing any existing entry. If OLD_CHILD is
+ NULL, and NAME already exists in dir, EEXIST is returned, otherwise, any
+ previous child is replaced and returned in OLD_CHILD. DIR should be
+ locked. */
+error_t treefs_mdir_add (struct treefs_node *dir, char *name,
+ struct treefs_node *child,
+ struct treefs_node **old_child);
+
+/* Remove any entry in DIR called NAME. If there is no such entry, ENOENT is
+ returned. If OLD_CHILD is non-NULL, any removed entry is returned in it.
+ DIR should be locked. */
+error_t treefs_mdir_remove (struct treefs_node *dir, char *name,
+ struct treefs_node **old_child);
+
+/* Returns in NODE any entry called NAME in DIR, or NULL (and ENOENT) if
+ there isn't such. DIR should be locked. */
+error_t treefs_mdir_get (struct treefs_node *dir, char *name,
+ struct treefs_node **node);
+
+/* Call FUN on each child of DIR; if FUN returns a non-zero value at any
+ point, stop iterating and return that value immediately. */
+error_t treefs_mdir_for_each (struct treefs_node *dir,
+ error_t (*fun)(struct treefs_node *node));
+
+/* ---------------------------------------------------------------- */
+/* Functions for dealing with node lists. */
+
+/* Return a new node list, or NULL if a memory allocation error occurs. */
+struct treefs_node_list *treefs_make_node_list ();
+
+/* Add NODE to LIST as NAME, replacing any existing entry. If OLD_NODE is
+ NULL, and an entry NAME already exists, EEXIST is returned, otherwise, any
+ previous child is replaced and returned in OLD_NODE. */
+error_t treefs_node_list_add (struct treefs_node_list *list, char *name,
+ struct treefs_node *node,
+ struct treefs_node **old_node);
+
+/* Remove any entry in LIST called NAME. If there is no such entry, ENOENT is
+ returned. If OLD_NODE is non-NULL, any removed entry is returned in it. */
+error_t treefs_node_list_remove (struct treefs_node_list *list, char *name,
+ struct treefs_node **old_node);
+
+/* Returns in NODE any entry called NAME in LIST, or NULL (and ENOENT) if
+ there isn't such. */
+error_t treefs_node_list_get (struct treefs_node_list *list, char *name,
+ struct treefs_node **node);
+
+/* Call FUN on each node in LIST; if FUN returns a non-zero value at any
+ point, stop iterating and return that value immediately. */
+error_t treefs_node_list_for_each (struct treefs_node_list *list,
+ error_t (*fun)(char *name,
+ struct treefs_node *node));
+
+/* ---------------------------------------------------------------- */
+/* Functions for manipulating hook vectors. */
+
+typedef void (*treefs_hook_vector_init_t[TREEFS_NUM_HOOKS])();
+
+extern treefs_hook_vector_init_t treefs_default_hooks;
+
+/* Returns a copy of the treefs hook vector HOOKS, or a zero'd vector if HOOKS
+ is NULL. If HOOKS is NULL, treefs_default_hooks is used. If a memory
+ allocation error occurs, NULL is returned. */
+treefs_hook_vector_t treefs_hooks_clone (treefs_hook_vector_t hooks);
+
+/* Copies each non-NULL entry in OVERRIDES into HOOKS. */
+void treefs_hooks_override (treefs_hook_vector_t hooks,
+ treefs_hook_vector_t overrides);
+
+/* Sets the hook NUM in HOOKS to HOOK. */
+void treefs_hooks_set (treefs_hook_vector_t hooks,
+ unsigned num, void (*hook)());
+
+/* ---------------------------------------------------------------- */
+/* Reference counting function (largely stolen from diskfs). */
+
+extern spin_lock_t treefs_node_refcnt_lock;
+
+/* Add a hard reference to a node. If there were no hard
+ references previously, then the node cannot be locked
+ (because you must hold a hard reference to hold the lock). */
+extern inline void
+treefs_node_ref (struct treefs_node *node)
+{
+ int new_ref;
+ spin_lock (&treefs_node_refcnt_lock);
+ node->refs++;
+ new_ref = (node->refs == 1);
+ spin_unlock (&treefs_node_refcnt_lock);
+ if (new_ref)
+ {
+ mutex_lock (&node->lock);
+ treefs_node_new_refs (node);
+ mutex_unlock (&node->lock);
+ }
+}
+
+/* Unlock node NODE and release a hard reference; if this is the last
+ hard reference and there are no links to the file then request
+ weak references to be dropped. */
+extern inline void
+treefs_node_release (struct treefs_node *node)
+{
+ int tried_drop_weak_refs = 0;
+
+ loop:
+ spin_lock (&treefs_node_refcnt_lock);
+ assert (node->refs);
+ node->refs--;
+ if (node->refs + node->weak_refs == 0)
+ treefs_node_drop (node);
+ else if (node->refs == 0 && !tried_drop_weak_refs)
+ {
+ spin_unlock (&treefs_node_refcnt_lock);
+ treefs_node_lost_refs (node);
+ if (treefs_node_unlinked (node))
+ {
+ /* There are no links. If there are weak references that
+ can be dropped, we can't let them postpone deallocation.
+ So attempt to drop them. But that's a user-supplied
+ routine, which might result in further recursive calls to
+ the ref-counting system. So we have to reacquire our
+ reference around the call to forestall disaster. */
+ spin_unlock (&treefs_node_refcnt_lock);
+ node->refs++;
+ spin_unlock (&treefs_node_refcnt_lock);
+
+ treefs_node_try_dropping_weak_refs (node);
+
+ /* But there's no value in looping forever in this
+ routine; only try to drop weak references once. */
+ tried_drop_weak_refs = 1;
+
+ /* Now we can drop the reference back... */
+ goto loop;
+ }
+ }
+ else
+ spin_unlock (&treefs_node_refcnt_lock);
+ mutex_unlock (&node->lock);
+}
+
+/* Release a hard reference on NODE. If NODE is locked by anyone, then
+ this cannot be the last hard reference (because you must hold a
+ hard reference in order to hold the lock). If this is the last
+ hard reference and there are no links, then request weak references
+ to be dropped. */
+extern inline void
+treefs_node_unref (struct treefs_node *node)
+{
+ int tried_drop_weak_refs = 0;
+
+ loop:
+ spin_lock (&treefs_node_refcnt_lock);
+ assert (node->refs);
+ node->refs--;
+ if (node->refs + node->weak_refs == 0)
+ {
+ mutex_lock (&node->lock);
+ treefs_node_drop (node);
+ }
+ else if (node->refs == 0)
+ {
+ mutex_lock (&node->lock);
+ spin_unlock (&treefs_node_refcnt_lock);
+ treefs_node_lost_refs (node);
+ if (treefs_node_unlinked(node) && !tried_drop_weak_refs)
+ {
+ /* Same issue here as in nodeut; see that for explanation */
+ spin_unlock (&treefs_node_refcnt_lock);
+ node->refs++;
+ spin_unlock (&treefs_node_refcnt_lock);
+
+ treefs_node_try_dropping_weak_refs (node);
+ tried_drop_weak_refs = 1;
+
+ /* Now we can drop the reference back... */
+ mutex_unlock (&node->lock);
+ goto loop;
+ }
+ mutex_unlock (&node->lock);
+ }
+ else
+ spin_unlock (&treefs_node_refcnt_lock);
+}
+
+/* Add a weak reference to a node. */
+extern inline void
+treefs_node_ref_weak (struct treefs_node *node)
+{
+ spin_lock (&treefs_node_refcnt_lock);
+ node->weak_refs++;
+ spin_unlock (&treefs_node_refcnt_lock);
+}
+
+/* Unlock node NODE and release a weak reference */
+extern inline void
+treefs_node_release_weak (struct treefs_node *node)
+{
+ spin_lock (&treefs_node_refcnt_lock);
+ assert (node->weak_refs);
+ node->weak_refs--;
+ if (node->refs + node->weak_refs == 0)
+ treefs_node_drop (node);
+ else
+ {
+ spin_unlock (&treefs_node_refcnt_lock);
+ mutex_unlock (&node->lock);
+ }
+}
+
+/* Release a weak reference on NODE. If NODE is locked by anyone, then
+ this cannot be the last reference (because you must hold a
+ hard reference in order to hold the lock). */
+extern inline void
+treefs_node_unref_weak (struct treefs_node *node)
+{
+ spin_lock (&treefs_node_refcnt_lock);
+ assert (node->weak_refs);
+ node->weak_refs--;
+ if (node->refs + node->weak_refs == 0)
+ {
+ mutex_lock (&node->lock);
+ treefs_node_drop (node);
+ }
+ else
+ spin_unlock (&treefs_node_refcnt_lock);
+}
+
+/* ---------------------------------------------------------------- */
+
+/* Return in PORT a send right for a new handle, pointing at the peropen PO,
+ with rights initialized from AUTH. */
+error_t
+treefs_peropen_create_right (struct treefs_peropen *po,
+ struct treefs_auth *auth,
+ mach_port_t *port);
+
+/* Return a send right for a new handle and a new peropen, pointing at NODE,
+ with rights initialized from AUTH. MODE and PARENT_PORT are used to
+ initialize the corresponding fields in the new peropen. */
+error_t
+treefs_node_create_right (struct treefs_node *node, int flags,
+ mach_port_t parent_port, struct treefs_auth *auth,
+ mach_port_t *port);
+
+/* ---------------------------------------------------------------- */
+/* Auth functions; copied from diskfs. */
+
+/* Return nonzero iff the user identified by AUTH has uid UID. */
+extern inline int
+treefs_auth_has_uid (struct treefs_auth *auth, uid_t uid)
+{
+ int i;
+ for (i = 0; i < auth->nuids; i++)
+ if (auth->uids[i] == uid)
+ return 1;
+ return 0;
+}
+
+/* Return nonzero iff the user identified by AUTH has group GID. */
+extern inline int
+treefs_auth_in_group (struct treefs_auth *auth, gid_t gid)
+{
+ int i;
+ for (i = 0; i < auth->ngids; i++)
+ if (auth->gids[i] == gid)
+ return 1;
+ return 0;
+}
+
+/* ---------------------------------------------------------------- */
+/* Helper routines for dealing with translators. */
+
+/* Return the active translator control port for NODE. If there is no
+ translator, active or passive, MACH_PORT_NULL is returned in CONTROL_PORT.
+ If there is a translator, it is started if necessary, and returned in
+ CONTROL_PORT. *DIR_PORT should be a port right to use as the new
+ translators parent directory. If it is MACH_PORT_NULL, a port is created
+ from DIR and PARENT_PORT and stored in *DIR_PORT; otherwise DIR and
+ PARENT_PORT are not used. Neither NODE or DIR should be locked when
+ calling this function. */
+error_t treefs_node_get_active_trans (struct treefs_node *node,
+ struct treefs_node *dir,
+ mach_port_t parent_port,
+ mach_port_t *control_port,
+ mach_port_t *dir_port);
+
+/* Drop the active translator CONTROL_PORT on NODE, unless it's no longer the
+ current active translator, in which case just drop a reference to it. */
+void treefs_node_drop_active_trans (struct treefs_node *node,
+ mach_port_t control_port);
+
+/* ---------------------------------------------------------------- */
+/* Basic node creation. */
+
+/* Create a basic node, with one reference and no user-specific fields
+ initialized, and return it in NODE */
+error_t
+treefs_create_node (struct treefs_fsys *fsys, struct treefs_node **node);
+
+/* Immediately destroy NODE, with no user-finalization. */
+error_t treefs_free_node (struct treefs_node *node);
+
+/* ---------------------------------------------------------------- */
+/* Some global variables. */
+
+/* The port class used by treefs to make filesystem control ports. */
+struct port_class *treefs_fsys_port_class;
+
+#endif /* __TREEFS_H__ */
diff --git a/mkinstalldirs b/mkinstalldirs
new file mode 100755
index 00000000..ac412b20
--- /dev/null
+++ b/mkinstalldirs
@@ -0,0 +1,40 @@
+#! /bin/sh
+# mkinstalldirs --- make directory hierarchy
+# Author: Noah Friedman <friedman@prep.ai.mit.edu>
+# Created: 1993-05-16
+# Public domain
+
+# $Id: mkinstalldirs,v 1.1 1996/07/18 04:35:29 mib Exp $
+
+errstatus=0
+
+for file
+do
+ set fnord `echo ":$file" | sed -ne 's/^:\//#/;s/^://;s/\// /g;s/^#/\//;p'`
+ shift
+
+ pathcomp=
+ for d
+ do
+ pathcomp="$pathcomp$d"
+ case "$pathcomp" in
+ -* ) pathcomp=./$pathcomp ;;
+ esac
+
+ if test ! -d "$pathcomp"; then
+ echo "mkdir $pathcomp" 1>&2
+
+ mkdir "$pathcomp" || lasterr=$?
+
+ if test ! -d "$pathcomp"; then
+ errstatus=$lasterr
+ fi
+ fi
+
+ pathcomp="$pathcomp/"
+ done
+done
+
+exit $errstatus
+
+# mkinstalldirs ends here
diff --git a/mount/mount.defs b/mount/mount.defs
new file mode 100644
index 00000000..7e97bb9b
--- /dev/null
+++ b/mount/mount.defs
@@ -0,0 +1,109 @@
+/* A server for keeping track of filesystems
+
+ Copyright (C) 1996 Free Software Foundation, Inc.
+
+ Written by Miles Bader <miles@gnu.ai.mit.edu>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <hurd/hurd_types.defs>
+
+subsystem mount 37000;
+
+import <hurd/mount_defs.h>;
+
+type mount_t = mach_port_t
+#ifdef MOUNT_INTRAN
+intran: MOUNT_INTRAN
+#endif
+#ifdef MOUNT_OUTTRAN
+outtran: MOUNT_OUTTRAN
+#endif
+#ifdef MOUNT_DESTRUCTOR
+destructor: MOUNT_DESTRUCTOR
+#endif
+;
+type mount_server_t = mach_port_t
+#ifdef MOUNT_SERVER_INTRAN
+intran: MOUNT_SERVER_INTRAN
+#endif
+#ifdef MOUNT_SERVER_OUTTRAN
+outtran: MOUNT_SERVER_OUTTRAN
+#endif
+#ifdef MOUNT_SERVER_DESTRUCTOR
+destructor: MOUNT_SERVER_DESTRUCTOR
+#endif
+;
+
+type mount_state_t = int ctype: mount_state_t;
+type mount_key_class_t = int ctype: mount_key_class_t;
+type mount_excl_t = int ctype: mount_excl_t;
+
+#ifdef MOUNT_IMPORTS
+MOUNT_IMPORTS
+#endif
+
+INTR_INTERFACE
+
+/* RPCs */
+
+/* Begin mounting the filesystem designated by KEY & KEY_CLASS; the mount is
+ initially assumed to have a mode of 0 (see mount_set_mode). EXCL is the
+ mount exclusion mode which applies to KEY (only the first EXCL argument
+ for a particular KEY is used). A mount reference is returned in MOUNT,
+ and the current state of that filesystem is returned in STATE (and may be
+ used to, e.g., cause the mount to be read-only if STATE is SUSPICIOUS). */
+routine mount_begin (
+ server : mount_server_t;
+ key : string_t;
+ key_class : mount_key_class_t;
+ excl : mount_excl_t;
+ out mount : mount_t;
+ out state : mount_state_t);
+
+/* Assert that MOUNT is no longer active. If CLEAN is true, then the state
+ of the filesystem should be changed to CLEAN; however if the state was
+ previously SUSPICIOUS, this is only done if CHECKED is true. */
+routine mount_end (
+ mount : mount_t;
+ clean : boolean_t;
+ checked : boolean_t);
+
+/* Indicate that MOUNT is a real mount. TRANSLATOR and MPOINT should be the
+ filesystem control port and the node which is being translated. TIMESTAMP
+ is used to validate this mount if a reconnection to the mount server
+ becomes necessary. */
+routine mount_set_translator (
+ mount : mount_t;
+ translator : fsys_t;
+ mpoint : file_t;
+ timestamp : time_spec_t);
+
+/* If CLEAN is true, then the state of the filesystem should be changed to
+ CLEAN; however if the state was previously SUSPICIOUS, this is only done
+ if CHECKED is true. */
+routine mount_set_clean (
+ mount : mount_t
+ clean : boolean_t;
+ checked : boolean_t);
+
+/* Change the current writable state of MOUNT to MODE, which should be a
+ bitmask containg MOUNT_READ and/or MOUNT_WRITE. If other current mounts
+ preclude this, then EBUSY is returned. If MODE contains MOUNT_FORCE and
+ there are conflicting mounts, an attempt is made to use the --suspend
+ option on the other filesystems in order to force the issue. */
+routine mount_set_mode (
+ mount : mount_t
+ mode : int);
diff --git a/mount/mount.h b/mount/mount.h
new file mode 100644
index 00000000..0d3eb855
--- /dev/null
+++ b/mount/mount.h
@@ -0,0 +1,72 @@
+/* Private definitions for the mount server
+
+ Copyright (C) 1996 Free Software Foundation, Inc.
+
+ Written by Miles Bader <miles@gnu.ai.mit.edu>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <hurd/ports.h>
+
+#include "mount_types.h"
+
+/* A particular mount of a filesystem. */
+struct mount
+{
+ struct port_info pi; /* libports header. */
+
+ /* The filesystem this a mount of. */
+ struct mount_fsys *fsys;
+
+ /* Modes of this mount, from the set MOUNT_READ, MOUNT_WRITE, &c. */
+ int mode;
+
+ /* The filesystem control port for its translator. This may
+ MACH_PORT_NULL, in which case it's not actually a filesystem (maybe it's
+ a fsck or something). */
+ fsys_t translator;
+
+ /* A timestamp associated with TRANSLATOR, used to validate state if the
+ mount server is restarted. */
+ struct timespec timestamp;
+
+ /* The place in the filesystem where this filesystem is mounted, using the
+ mount server's root node. */
+ char *mount_point;
+
+ /* The next mount of this filesystem. */
+ struct mount *next;
+};
+
+struct mount_fsys
+{
+ /* A string identifying the `backing store' associated with this
+ filesystem, who's interpretation depends on KEY_CLASS:
+ MOUNT_KEY_UNKNOWN -- no interpretation, just a string
+ MOUNT_KEY_FILE -- KEY is a filename
+ MOUNT_KEY_DEVICE -- KEY is a (mach) device name
+ No two filesystems can have the same KEY and KEY_CLASS. */
+ char *key;
+ enum mount_key_class key_class;
+
+ /* In what condition we think the filesystem is. */
+ enum mount_state state;
+
+ /* How this file system deals with multiple mount requests. */
+ enum mount_excl excl;
+
+ /* Active mounts of this filesystem. */
+ struct mount *mounts;
+};
diff --git a/mount/mount_types.h b/mount/mount_types.h
new file mode 100644
index 00000000..f72d3a53
--- /dev/null
+++ b/mount/mount_types.h
@@ -0,0 +1,61 @@
+/* Exported types for the mount server
+
+ Copyright (C) 1996 Free Software Foundation, Inc.
+
+ Written by Miles Bader <miles@gnu.ai.mit.edu>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* Modes a particular mount may have. */
+#define MOUNT_READ 0x1 /* We only read. */
+#define MOUNT_WRITE 0x2 /* We write too. */
+#define MOUNT_FORCE 0x4 /* Used to try forcing a writable mount. */
+
+/* The condition we think a file system is in (this refers to the permanent
+ storage from which it is backed, not an active file system). */
+enum mount_state
+{
+ MOUNT_STATE_UNKNOWN, /* Just so. When this value is passed to a
+ mount routine that takes a state argument,
+ it usually means `keep the last known
+ state'. */
+ MOUNT_STATE_SUSPICIOUS, /* We think it may have been compromised. */
+ MOUNT_STATE_DIRTY, /* May be transiently inconsistent. This is
+ the normal state for an active writable
+ file system. */
+ MOUNT_STATE_CLEAN /* Peachy. */
+};
+typedef enum mount_state mount_state_t; /* For mig's use. */
+
+/* How the key associated with a filesystem is interpreted. */
+enum mount_key_class
+{
+ MOUNT_KEY_UNKNOWN, /* */
+ MOUNT_KEY_FILE, /* A file (including e.g., `/dev/rsd0a'). */
+ MOUNT_KEY_DEVICE /* A mach device name. */
+};
+typedef enum mount_key_class mount_key_class_t; /* For mig's use. */
+
+/* Types of multiple mounts of a single filesystem that are allowed. */
+enum mount_excl
+{
+ MOUNT_EXCL_NONE, /* Both multiple readers and multiple writers
+ allowed; some external private protocol
+ must be used to main consistency. */
+ MOUNT_EXCL_WRITE, /* Multiple readers allowed, but if there's a
+ writer, it must be the only mount. */
+ MOUNT_EXCL_RDWR /* Only a single mount of any type allowed. */
+};
+typedef enum mount_excl mount_excl_t; /* For mig */
diff --git a/nfs/pager.c b/nfs/pager.c
new file mode 100644
index 00000000..687a0e2f
--- /dev/null
+++ b/nfs/pager.c
@@ -0,0 +1,448 @@
+/*
+ Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+ Written by Michael I. Bushnell, p/BSG.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+
+#include "nfs.h"
+#include <unistd.h>
+#include <hurd/pager.h>
+#include <netinet/in.h>
+#include <string.h>
+
+struct user_pager_info
+{
+ struct node *np;
+ struct pager *p;
+ int max_prot;
+};
+
+struct pager_cache_rec
+{
+ struct pager_cache_rec *next;
+ vm_offset_t offset;
+ struct pager *p;
+ time_t fetched;
+};
+
+static struct pager_cache_rec *pager_cache_recs;
+static spin_lock_t pager_cache_rec_lock = SPIN_LOCK_INITIALIZER;
+static spin_lock_t node2pagelock = SPIN_LOCK_INITIALIZER;
+static struct port_bucket *pager_bucket;
+
+void
+register_new_page (struct pager *p, vm_offset_t offset)
+{
+ struct pager_cache_rec *pc;
+
+ pc = malloc (sizeof (struct pager_cache_rec));
+ pc->offset = offset;
+ pc->p = p;
+ ports_port_ref (p);
+ pc->fetched = mapped_time->seconds;
+
+ spin_lock (&pager_cache_rec_lock);
+ pc->next = pager_cache_recs;
+ pager_cache_recs = pc;
+ spin_unlock (&pager_cache_rec_lock);
+}
+
+any_t
+flush_pager_cache_thread (any_t foo2)
+{
+ struct pager_cache_rec *pc, *next, **ppc, *list;
+
+ for (;;)
+ {
+ sleep (1);
+
+ /* Dequeue from the main list and queue locally the recs
+ for expired pages. */
+ list = 0;
+ spin_lock (&pager_cache_rec_lock);
+ for (pc = pager_cache_recs, ppc = &pager_cache_recs;
+ pc;
+ ppc = &pc->next, pc = next)
+ {
+ next = pc->next;
+ if (mapped_time->seconds - pc->fetched > cache_timeout)
+ {
+ *ppc = pc->next;
+ pc->next = list;
+ list = pc;
+ }
+ }
+ spin_unlock (&pager_cache_rec_lock);
+
+ /* And now, one at a time, expire them */
+ for (pc = list; pc; pc = next)
+ {
+ pager_return_some (pc->p, pc->offset, vm_page_size, 0);
+ next = pc->next;
+ ports_port_deref (pc->p);
+ free (pc);
+ }
+ }
+}
+
+error_t
+pager_read_page (struct user_pager_info *pager,
+ vm_offset_t page,
+ vm_address_t *buf,
+ int *writelock)
+{
+ error_t err;
+ int *p;
+ void *rpcbuf;
+ struct node *np;
+ size_t amt, thisamt, trans_len;
+ void *data;
+ off_t offset;
+
+ np = pager->np;
+
+ mutex_lock (&np->lock);
+
+ vm_allocate (mach_task_self (), buf, vm_page_size, 1);
+ data = (char *) *buf;
+ amt = vm_page_size;
+ offset = page;
+
+ while (amt)
+ {
+ thisamt = amt;
+ if (thisamt > read_size)
+ thisamt = read_size;
+
+ p = nfs_initialize_rpc (NFSPROC_READ, (struct netcred *)-1, 0,
+ &rpcbuf, np, -1);
+ p = xdr_encode_fhandle (p, &np->nn->handle);
+ *p++ = htonl (offset);
+ *p++ = htonl (vm_page_size);
+ *p++ = 0;
+
+ err = conduct_rpc (&rpcbuf, &p);
+ if (!err)
+ err = nfs_error_trans (ntohl (*p++));
+ if (err)
+ {
+ mutex_unlock (&np->lock);
+ free (rpcbuf);
+ vm_deallocate (mach_task_self (), *buf, vm_page_size);
+ return err;
+ }
+
+ p = register_fresh_stat (np, p);
+ trans_len = ntohl (*p++);
+ if (trans_len > thisamt)
+ trans_len = thisamt; /* ??? */
+
+ bcopy (p, data, trans_len);
+
+ free (rpcbuf);
+
+ data += trans_len;
+ offset += trans_len;
+ amt -= trans_len;
+
+ /* If we got a short count, we're all done. */
+ if (trans_len < thisamt)
+ break;
+ }
+
+ register_new_page (pager->p, page);
+ mutex_unlock (&np->lock);
+ return 0;
+}
+
+
+error_t
+pager_write_page (struct user_pager_info *pager,
+ vm_offset_t page,
+ vm_address_t buf)
+{
+ int *p;
+ void *rpcbuf;
+ error_t err;
+ size_t amt, thisamt;
+ off_t offset;
+ struct node *np;
+ void *data;
+
+ np = pager->np;
+ mutex_lock (&np->lock);
+
+ amt = vm_page_size;
+ offset = page;
+ data = (void *) buf;
+
+ while (amt)
+ {
+ thisamt = amt;
+ if (amt > write_size)
+ amt = write_size;
+
+ p = nfs_initialize_rpc (NFSPROC_WRITE, (struct netcred *) -1,
+ amt, &rpcbuf, np, -1);
+ p = xdr_encode_fhandle (p, &np->nn->handle);
+ *p++ = 0;
+ *p++ = htonl (offset);
+ *p++ = 0;
+ p = xdr_encode_data (p, data, thisamt);
+
+ err = conduct_rpc (&rpcbuf, &p);
+ if (!err)
+ err = nfs_error_trans (ntohl (*p++));
+ if (err)
+ {
+ free (rpcbuf);
+ vm_deallocate (mach_task_self (), buf, vm_page_size);
+ return err;
+ }
+ register_fresh_stat (np, p);
+ free (rpcbuf);
+ amt -= thisamt;
+ data += thisamt;
+ offset += thisamt;
+ }
+
+ vm_deallocate (mach_task_self (), buf, vm_page_size);
+ mutex_unlock (&np->lock);
+ return 0;
+}
+
+error_t
+pager_unlock_page (struct user_pager_info *pager,
+ vm_offset_t address)
+{
+ abort ();
+}
+
+error_t
+pager_report_extent (struct user_pager_info *pager,
+ vm_address_t *offset,
+ vm_size_t *size)
+{
+ struct node *np;
+ error_t err;
+
+ np = pager->np;
+ mutex_lock (&np->lock);
+
+ err = netfs_validate_stat (np, 0);
+ if (!err)
+ *size = round_page (np->nn_stat.st_size);
+ mutex_unlock (&np->lock);
+ return err;
+}
+
+void
+pager_clear_user_data (struct user_pager_info *upi)
+{
+ spin_lock (&node2pagelock);
+ if (upi->np->nn->fileinfo == upi)
+ upi->np->nn->fileinfo = 0;
+ spin_unlock (&node2pagelock);
+ netfs_nrele (upi->np);
+ free (upi);
+}
+
+void
+pager_dropweak (struct user_pager_info *upi)
+{
+ abort ();
+}
+
+mach_port_t
+netfs_get_filemap (struct node *np, vm_prot_t prot)
+{
+ struct user_pager_info *upi;
+ mach_port_t right;
+
+ spin_lock (&node2pagelock);
+ do
+ if (!np->nn->fileinfo)
+ {
+ upi = malloc (sizeof (struct user_pager_info));
+ upi->np = np;
+ netfs_nref (np);
+ upi->max_prot = prot;
+ upi->p = pager_create (upi, pager_bucket, 1, MEMORY_OBJECT_COPY_NONE);
+ np->nn->fileinfo = upi;
+ right = pager_get_port (np->nn->fileinfo->p);
+ ports_port_deref (np->nn->fileinfo->p);
+ }
+ else
+ {
+ np->nn->fileinfo->max_prot |= prot;
+ /* Because NP->dn->fileinfo->p is not a real reference,
+ this might be nearly deallocated. If that's so, then
+ the port right will be null. In that case, clear here
+ and loop. The deallocation will complete separately. */
+ right = pager_get_port (np->nn->fileinfo->p);
+ if (right == MACH_PORT_NULL)
+ np->nn->fileinfo = 0;
+ }
+ while (right == MACH_PORT_NULL);
+
+ spin_unlock (&node2pagelock);
+
+ mach_port_insert_right (mach_task_self (), right, right,
+ MACH_MSG_TYPE_MAKE_SEND);
+ return right;
+}
+
+void
+drop_pager_softrefs (struct node *np)
+{
+ struct user_pager_info *upi;
+
+ spin_lock (&node2pagelock);
+ upi = np->nn->fileinfo;
+ if (upi)
+ ports_port_ref (upi->p);
+ spin_unlock (&node2pagelock);
+
+ if (upi)
+ {
+ pager_change_attributes (upi->p, 0, MEMORY_OBJECT_COPY_NONE, 0);
+ ports_port_deref (upi->p);
+ }
+}
+
+void
+allow_pager_softrefs (struct node *np)
+{
+ struct user_pager_info *upi;
+
+ spin_lock (&node2pagelock);
+ upi = np->nn->fileinfo;
+ if (upi)
+ ports_port_ref (upi->p);
+ spin_unlock (&node2pagelock);
+
+ if (upi)
+ {
+ pager_change_attributes (upi->p, 1, MEMORY_OBJECT_COPY_NONE, 0);
+ ports_port_deref (upi->p);
+ }
+}
+
+void
+block_caching ()
+{
+ error_t block_cache (void *arg)
+ {
+ struct pager *p = arg;
+ pager_change_attributes (p, 0, MEMORY_OBJECT_COPY_NONE, 1);
+ return 0;
+ }
+ ports_bucket_iterate (pager_bucket, block_cache);
+}
+
+void
+enable_caching ()
+{
+ error_t enable_cache (void *arg)
+ {
+ struct pager *p = arg;
+ struct user_pager_info *upi = pager_get_upi (p);
+
+ pager_change_attributes (p, 1, MEMORY_OBJECT_COPY_NONE, 0);
+ return 0;
+ }
+
+ ports_bucket_iterate (pager_bucket, enable_cache);
+}
+
+int
+netfs_pager_users ()
+{
+ int npagers = ports_count_bucket (pager_bucket);
+
+ if (!npagers)
+ return 0;
+
+ block_caching ();
+ /* Give it a sec; the kernel doesn't issue the shutdown right away */
+ sleep (1);
+ npagers = ports_count_bucket (pager_bucket);
+ if (!npagers)
+ return 0;
+
+ enable_caching ();
+
+ ports_enable_bucket (pager_bucket);
+}
+
+vm_prot_t
+netfs_max_user_pager_prot ()
+{
+ vm_prot_t max_prot;
+ int npagers = ports_count_bucket (pager_bucket);
+
+ if (npagers)
+ {
+ error_t add_pager_max_prot (void *v_p)
+ {
+ struct pager *p = v_p;
+ struct user_pager_info *upi = pager_get_upi (p);
+ max_prot |= upi->max_prot;
+ return max_prot == (VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE);
+ }
+
+ block_caching ();
+ sleep (1);
+
+ ports_bucket_iterate (pager_bucket, add_pager_max_prot);
+ enable_caching ();
+ }
+
+ ports_enable_bucket (pager_bucket);
+ return max_prot;
+}
+
+void
+netfs_shutdown_pager ()
+{
+ error_t shutdown_one (void *arg)
+ {
+ pager_shutdown ((struct pager *) arg);
+ return 0;
+ }
+
+ ports_bucket_iterate (pager_bucket, shutdown_one);
+}
+
+void
+netfs_sync_everything (int wait)
+{
+ error_t sync_one (void *arg)
+ {
+ pager_sync ((struct pager *) arg, wait);
+ return 0;
+ }
+ ports_bucket_iterate (pager_bucket, sync_one);
+}
+
+void
+pager_initialize (void)
+{
+ pager_bucket = ports_create_bucket ();
+ cthread_detach (cthread_fork (flush_pager_cache_thread, 0));
+
diff --git a/nfs/rpcsvc/mount.h b/nfs/rpcsvc/mount.h
new file mode 100644
index 00000000..2dc3dc88
--- /dev/null
+++ b/nfs/rpcsvc/mount.h
@@ -0,0 +1,81 @@
+#define MNTPATHLEN 1024
+#define MNTNAMLEN 255
+#define FHSIZE 32
+
+typedef char fhandle[FHSIZE];
+bool_t xdr_fhandle();
+
+
+struct fhstatus {
+ u_int fhs_status;
+ union {
+ fhandle fhs_fhandle;
+ } fhstatus_u;
+};
+typedef struct fhstatus fhstatus;
+bool_t xdr_fhstatus();
+
+
+typedef char *dirpath;
+bool_t xdr_dirpath();
+
+
+typedef char *name;
+bool_t xdr_name();
+
+
+typedef struct mountbody *mountlist;
+bool_t xdr_mountlist();
+
+
+struct mountbody {
+ name ml_hostname;
+ dirpath ml_directory;
+ mountlist ml_next;
+};
+typedef struct mountbody mountbody;
+bool_t xdr_mountbody();
+
+
+typedef struct groupnode *groups;
+bool_t xdr_groups();
+
+
+struct groupnode {
+ name gr_name;
+ groups gr_next;
+};
+typedef struct groupnode groupnode;
+bool_t xdr_groupnode();
+
+
+typedef struct exportnode *exports;
+bool_t xdr_exports();
+
+
+struct exportnode {
+ dirpath ex_dir;
+ groups ex_groups;
+ exports ex_next;
+};
+typedef struct exportnode exportnode;
+bool_t xdr_exportnode();
+
+
+#define MOUNTPROG ((u_long)100005)
+#define MOUNTVERS ((u_long)1)
+#define MOUNTPROC_NULL ((u_long)0)
+extern void *mountproc_null_1();
+#define MOUNTPROC_MNT ((u_long)1)
+extern fhstatus *mountproc_mnt_1();
+#define MOUNTPROC_DUMP ((u_long)2)
+extern mountlist *mountproc_dump_1();
+#define MOUNTPROC_UMNT ((u_long)3)
+extern void *mountproc_umnt_1();
+#define MOUNTPROC_UMNTALL ((u_long)4)
+extern void *mountproc_umntall_1();
+#define MOUNTPROC_EXPORT ((u_long)5)
+extern exports *mountproc_export_1();
+#define MOUNTPROC_EXPORTALL ((u_long)6)
+extern exports *mountproc_exportall_1();
+
diff --git a/nfs/rpcsvc/nfs_prot.h b/nfs/rpcsvc/nfs_prot.h
new file mode 100644
index 00000000..7f974930
--- /dev/null
+++ b/nfs/rpcsvc/nfs_prot.h
@@ -0,0 +1,343 @@
+#define NFS_PORT 2049
+#define NFS_MAXDATA 8192
+#define NFS_MAXPATHLEN 1024
+#define NFS_MAXNAMLEN 255
+#define NFS_FHSIZE 32
+#define NFS_COOKIESIZE 4
+#define NFS_FIFO_DEV -1
+#define NFSMODE_FMT 0170000
+#define NFSMODE_DIR 0040000
+#define NFSMODE_CHR 0020000
+#define NFSMODE_BLK 0060000
+#define NFSMODE_REG 0100000
+#define NFSMODE_LNK 0120000
+#define NFSMODE_SOCK 0140000
+#define NFSMODE_FIFO 0010000
+
+enum nfsstat {
+ NFS_OK = 0,
+ NFSERR_PERM = 1,
+ NFSERR_NOENT = 2,
+ NFSERR_IO = 5,
+ NFSERR_NXIO = 6,
+ NFSERR_ACCES = 13,
+ NFSERR_EXIST = 17,
+ NFSERR_NODEV = 19,
+ NFSERR_NOTDIR = 20,
+ NFSERR_ISDIR = 21,
+ NFSERR_FBIG = 27,
+ NFSERR_NOSPC = 28,
+ NFSERR_ROFS = 30,
+ NFSERR_NAMETOOLONG = 63,
+ NFSERR_NOTEMPTY = 66,
+ NFSERR_DQUOT = 69,
+ NFSERR_STALE = 70,
+ NFSERR_WFLUSH = 99,
+};
+typedef enum nfsstat nfsstat;
+bool_t xdr_nfsstat();
+
+
+enum ftype {
+ NFNON = 0,
+ NFREG = 1,
+ NFDIR = 2,
+ NFBLK = 3,
+ NFCHR = 4,
+ NFLNK = 5,
+ NFSOCK = 6,
+ NFBAD = 7,
+ NFFIFO = 8,
+};
+typedef enum ftype ftype;
+bool_t xdr_ftype();
+
+
+struct nfs_fh {
+ char data[NFS_FHSIZE];
+};
+typedef struct nfs_fh nfs_fh;
+bool_t xdr_nfs_fh();
+
+
+struct nfstime {
+ u_int seconds;
+ u_int useconds;
+};
+typedef struct nfstime nfstime;
+bool_t xdr_nfstime();
+
+
+struct fattr {
+ ftype type;
+ u_int mode;
+ u_int nlink;
+ u_int uid;
+ u_int gid;
+ u_int size;
+ u_int blocksize;
+ u_int rdev;
+ u_int blocks;
+ u_int fsid;
+ u_int fileid;
+ nfstime atime;
+ nfstime mtime;
+ nfstime ctime;
+};
+typedef struct fattr fattr;
+bool_t xdr_fattr();
+
+
+struct sattr {
+ u_int mode;
+ u_int uid;
+ u_int gid;
+ u_int size;
+ nfstime atime;
+ nfstime mtime;
+};
+typedef struct sattr sattr;
+bool_t xdr_sattr();
+
+
+typedef char *filename;
+bool_t xdr_filename();
+
+
+typedef char *nfspath;
+bool_t xdr_nfspath();
+
+
+struct attrstat {
+ nfsstat status;
+ union {
+ fattr attributes;
+ } attrstat_u;
+};
+typedef struct attrstat attrstat;
+bool_t xdr_attrstat();
+
+
+struct sattrargs {
+ nfs_fh file;
+ sattr attributes;
+};
+typedef struct sattrargs sattrargs;
+bool_t xdr_sattrargs();
+
+
+struct diropargs {
+ nfs_fh dir;
+ filename name;
+};
+typedef struct diropargs diropargs;
+bool_t xdr_diropargs();
+
+
+struct diropokres {
+ nfs_fh file;
+ fattr attributes;
+};
+typedef struct diropokres diropokres;
+bool_t xdr_diropokres();
+
+
+struct diropres {
+ nfsstat status;
+ union {
+ diropokres diropres;
+ } diropres_u;
+};
+typedef struct diropres diropres;
+bool_t xdr_diropres();
+
+
+struct readlinkres {
+ nfsstat status;
+ union {
+ nfspath data;
+ } readlinkres_u;
+};
+typedef struct readlinkres readlinkres;
+bool_t xdr_readlinkres();
+
+
+struct readargs {
+ nfs_fh file;
+ u_int offset;
+ u_int count;
+ u_int totalcount;
+};
+typedef struct readargs readargs;
+bool_t xdr_readargs();
+
+
+struct readokres {
+ fattr attributes;
+ struct {
+ u_int data_len;
+ char *data_val;
+ } data;
+};
+typedef struct readokres readokres;
+bool_t xdr_readokres();
+
+
+struct readres {
+ nfsstat status;
+ union {
+ readokres reply;
+ } readres_u;
+};
+typedef struct readres readres;
+bool_t xdr_readres();
+
+
+struct writeargs {
+ nfs_fh file;
+ u_int beginoffset;
+ u_int offset;
+ u_int totalcount;
+ struct {
+ u_int data_len;
+ char *data_val;
+ } data;
+};
+typedef struct writeargs writeargs;
+bool_t xdr_writeargs();
+
+
+struct createargs {
+ diropargs where;
+ sattr attributes;
+};
+typedef struct createargs createargs;
+bool_t xdr_createargs();
+
+
+struct renameargs {
+ diropargs from;
+ diropargs to;
+};
+typedef struct renameargs renameargs;
+bool_t xdr_renameargs();
+
+
+struct linkargs {
+ nfs_fh from;
+ diropargs to;
+};
+typedef struct linkargs linkargs;
+bool_t xdr_linkargs();
+
+
+struct symlinkargs {
+ diropargs from;
+ nfspath to;
+ sattr attributes;
+};
+typedef struct symlinkargs symlinkargs;
+bool_t xdr_symlinkargs();
+
+
+typedef char nfscookie[NFS_COOKIESIZE];
+bool_t xdr_nfscookie();
+
+
+struct readdirargs {
+ nfs_fh dir;
+ nfscookie cookie;
+ u_int count;
+};
+typedef struct readdirargs readdirargs;
+bool_t xdr_readdirargs();
+
+
+struct entry {
+ u_int fileid;
+ filename name;
+ nfscookie cookie;
+ struct entry *nextentry;
+};
+typedef struct entry entry;
+bool_t xdr_entry();
+
+
+struct dirlist {
+ entry *entries;
+ bool_t eof;
+};
+typedef struct dirlist dirlist;
+bool_t xdr_dirlist();
+
+
+struct readdirres {
+ nfsstat status;
+ union {
+ dirlist reply;
+ } readdirres_u;
+};
+typedef struct readdirres readdirres;
+bool_t xdr_readdirres();
+
+
+struct statfsokres {
+ u_int tsize;
+ u_int bsize;
+ u_int blocks;
+ u_int bfree;
+ u_int bavail;
+};
+typedef struct statfsokres statfsokres;
+bool_t xdr_statfsokres();
+
+
+struct statfsres {
+ nfsstat status;
+ union {
+ statfsokres reply;
+ } statfsres_u;
+};
+typedef struct statfsres statfsres;
+bool_t xdr_statfsres();
+
+
+#define NFS_PROGRAM ((u_long)100003)
+#define NFS_VERSION ((u_long)2)
+#define NFSPROC_NULL ((u_long)0)
+extern void *nfsproc_null_2();
+#define NFSPROC_GETATTR ((u_long)1)
+extern attrstat *nfsproc_getattr_2();
+#define NFSPROC_SETATTR ((u_long)2)
+extern attrstat *nfsproc_setattr_2();
+#define NFSPROC_ROOT ((u_long)3)
+extern void *nfsproc_root_2();
+#define NFSPROC_LOOKUP ((u_long)4)
+extern diropres *nfsproc_lookup_2();
+#define NFSPROC_READLINK ((u_long)5)
+extern readlinkres *nfsproc_readlink_2();
+#define NFSPROC_READ ((u_long)6)
+extern readres *nfsproc_read_2();
+#define NFSPROC_WRITECACHE ((u_long)7)
+extern void *nfsproc_writecache_2();
+#define NFSPROC_WRITE ((u_long)8)
+extern attrstat *nfsproc_write_2();
+#define NFSPROC_CREATE ((u_long)9)
+extern diropres *nfsproc_create_2();
+#define NFSPROC_REMOVE ((u_long)10)
+extern nfsstat *nfsproc_remove_2();
+#define NFSPROC_RENAME ((u_long)11)
+extern nfsstat *nfsproc_rename_2();
+#define NFSPROC_LINK ((u_long)12)
+extern nfsstat *nfsproc_link_2();
+#define NFSPROC_SYMLINK ((u_long)13)
+extern nfsstat *nfsproc_symlink_2();
+#define NFSPROC_MKDIR ((u_long)14)
+extern diropres *nfsproc_mkdir_2();
+#define NFSPROC_RMDIR ((u_long)15)
+extern nfsstat *nfsproc_rmdir_2();
+#define NFSPROC_READDIR ((u_long)16)
+extern readdirres *nfsproc_readdir_2();
+#define NFSPROC_STATFS ((u_long)17)
+extern statfsres *nfsproc_statfs_2();
+
diff --git a/nfsd/Makefile b/nfsd/Makefile
new file mode 100644
index 00000000..4460b4ba
--- /dev/null
+++ b/nfsd/Makefile
@@ -0,0 +1,34 @@
+#
+# Copyright (C) 1996 Free Software Foundation, Inc.
+# Written by Michael I. Bushnell, p/BSG.
+#
+# This file is part of the GNU Hurd.
+#
+# The GNU Hurd is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2, or (at
+# your option) any later version.
+#
+# The GNU Hurd is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
+
+dir := nfsd
+makemode := utility
+
+SRCS = cache.c loop.c main.c ops.c fsys.c xdr.c
+OBJS = $(subst .c,.o,$(SRCS))
+LCLHDRS = nfsd.h
+target = nfsd
+installationdir = $(sbindir)
+
+include ../Makeconf
+
+CPPFLAGS += -DLOCALSTATEDIR=$(localstatedir)
+
+nfsd: ../libthreads/libthreads.a ../libshouldbeinlibc/libshouldbeinlibc.a \ No newline at end of file
diff --git a/nfsd/cache.c b/nfsd/cache.c
new file mode 100644
index 00000000..745a7c8e
--- /dev/null
+++ b/nfsd/cache.c
@@ -0,0 +1,496 @@
+/*
+ Copyright (C) 1996 Free Software Foundation, Inc.
+ Written by Michael I. Bushnell, p/BSG.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+
+#include <string.h>
+#include <hurd/fsys.h>
+#include <assert.h>
+#include <string.h>
+#include "nfsd.h"
+
+
+#undef TRUE
+#undef FALSE
+#define malloc spoogie_woogie /* ugh^2. */
+#include <rpc/types.h>
+#include <rpc/auth.h>
+#include <rpc/auth_unix.h>
+#undef malloc
+
+#define IDHASH_TABLE_SIZE 1024
+#define FHHASH_TABLE_SIZE 1024
+#define REPLYHASH_TABLE_SIZE 1024
+
+
+static struct idspec *idhashtable[IDHASH_TABLE_SIZE];
+spin_lock_t idhashlock = SPIN_LOCK_INITIALIZER;
+static int nfreeids;
+static int leastidlastuse;
+
+/* Compare I against the specified set of users/groups. */
+/* Use of int in decl of UIDS and GIDS is correct here; that's
+ the NFS type because they come in in known 32 bit slots. */
+static int
+idspec_compare (struct idspec *i, int nuids, int ngids,
+ int *uids, int *gids)
+{
+ if (i->nuids != nuids
+ || i->ngids != ngids)
+ return 0;
+
+ assert (sizeof (int) == sizeof (uid_t));
+
+ if (bcmp (i->uids, uids, nuids * sizeof (uid_t))
+ || bcmp (i->gids, gids, ngids * sizeof (gid_t)))
+ return 0;
+
+ return 1;
+}
+
+/* Compute a hash value for a given user spec */
+static int
+idspec_hash (int nuids, int ngids, int *uids, int *gids)
+{
+ int hash, n;
+
+ hash = nuids + ngids;
+ for (n = 0; n < ngids; n++)
+ hash += gids[n];
+ for (n = 0; n < nuids; n++)
+ hash += uids[n];
+ hash %= IDHASH_TABLE_SIZE;
+ return hash;
+}
+
+/* Lookup a user spec in the hash table and allocate a reference */
+static struct idspec *
+idspec_lookup (int nuids, int ngids, int *uids, int *gids)
+{
+ int hash;
+ struct idspec *i;
+
+ hash = idspec_hash (nuids, ngids, uids, gids);
+
+ spin_lock (&idhashlock);
+ for (i = idhashtable[hash]; i; i = i->next)
+ if (idspec_compare (i, nuids, ngids, uids, gids))
+ {
+ i->references++;
+ if (i->references == 1)
+ nfreeids--;
+ spin_unlock (&idhashlock);
+ return i;
+ }
+
+ assert (sizeof (uid_t) == sizeof (int));
+ i = malloc (sizeof (struct idspec));
+ i->nuids = nuids;
+ i->ngids = ngids;
+ i->uids = malloc (nuids * sizeof (uid_t));
+ i->gids = malloc (ngids * sizeof (gid_t));
+ bcopy (uids, i->uids, nuids * sizeof (uid_t));
+ bcopy (gids, i->gids, ngids * sizeof (gid_t));
+ i->references = 1;
+
+ i->next = idhashtable[hash];
+ if (idhashtable[hash])
+ idhashtable[hash]->prevp = &i->next;
+ i->prevp = &idhashtable[hash];
+ idhashtable[hash] = i;
+
+ spin_unlock (&idhashlock);
+ return i;
+}
+
+int *
+process_cred (int *p, struct idspec **credp)
+{
+ int type;
+ int len;
+ int *uid;
+ int *gids;
+ int ngids;
+ int firstgid;
+ int i;
+
+ type = ntohl (*p++);
+
+ if (type != AUTH_UNIX)
+ {
+ int size = ntohl (*p++);
+ *credp = idspec_lookup (0, 0, 0, 0);
+ return p + INTSIZE (size);
+ }
+
+ p++; /* skip size */
+ p++; /* skip seconds */
+ len = ntohl (*p++);
+ p += INTSIZE (len); /* skip hostname */
+
+ uid = p++; /* remember loc of uid */
+ *uid = ntohl (*uid);
+
+ firstgid = *p++; /* remember first gid */
+ gids = p; /* here's where the array will start */
+ ngids = ntohl (*p++);
+
+ /* Now swap the first gid to be the first element of the array */
+ *gids = firstgid;
+ ngids++; /* and count it */
+
+ /* And byteswap the gids */
+ for (i = 1; i < ngids; i++)
+ gids[i] = ntohl (gids[i]);
+
+ /* Next is the verf field; skip it entirely */
+ p++; /* skip id */
+ len = htonl (*p++);
+ p += INTSIZE (len);
+
+ *credp = idspec_lookup (1, ngids, uid, gids);
+ return p;
+}
+
+void
+cred_rele (struct idspec *i)
+{
+ spin_lock (&idhashlock);
+ i->references--;
+ if (i->references == 0)
+ {
+ i->lastuse = mapped_time->seconds;
+ if (i->lastuse < leastidlastuse || nfreeids == 0)
+ leastidlastuse = i->lastuse;
+ nfreeids++;
+ }
+ spin_unlock (&idhashlock);
+}
+
+void
+cred_ref (struct idspec *i)
+{
+ spin_lock (&idhashlock);
+ assert (i->references);
+ i->references++;
+ spin_unlock (&idhashlock);
+}
+
+void
+scan_creds ()
+{
+ struct idspec *i;
+ int n;
+ int newleast = mapped_time->seconds;
+
+ spin_lock (&idhashlock);
+ if (mapped_time->seconds - leastidlastuse > ID_KEEP_TIMEOUT)
+ for (n = 0; n < IDHASH_TABLE_SIZE && nfreeids; n++)
+ for (i = idhashtable[n]; i && nfreeids; i = i->next)
+ if (!i->references
+ && mapped_time->seconds - i->lastuse > ID_KEEP_TIMEOUT)
+ {
+ nfreeids--;
+ *i->prevp = i->next;
+ if (i->next)
+ i->next->prevp = i->prevp;
+ free (i->uids);
+ free (i->gids);
+ free (i);
+ }
+ else
+ if (!i->references && newleast > i->lastuse)
+ newleast = i->lastuse;
+
+ /* If we didn't bail early, then this is valid */
+ if (nfreeids)
+ leastidlastuse = newleast;
+ spin_unlock (&idhashlock);
+}
+
+
+
+static struct cache_handle *fhhashtable[FHHASH_TABLE_SIZE];
+struct mutex fhhashlock = MUTEX_INITIALIZER;
+static int nfreefh;
+static int leastfhlastuse;
+
+static int
+fh_hash (char *fhandle, struct idspec *i)
+{
+ int hash = 0, n;
+
+ for (n = 0; n < NFS_FHSIZE; n++)
+ hash += fhandle[n];
+ hash += (int) i >> 6;
+ return hash;
+}
+
+int *
+lookup_cache_handle (int *p, struct cache_handle **cp, struct idspec *i)
+{
+ int hash;
+ struct cache_handle *c;
+ fsys_t fsys;
+ file_t port;
+
+ hash = fh_hash ((char *)p, i);
+ mutex_lock (&fhhashlock);
+ for (c = fhhashtable[hash]; c; c = c->next)
+ if (c->ids == i && ! bcmp (c->handle, p, NFS_FHSIZE))
+ {
+ if (c->references == 0)
+ nfreefh--;
+ c->references++;
+ mutex_unlock (&fhhashlock);
+ *cp = c;
+ return p + NFS_FHSIZE / sizeof (int);
+ }
+
+ /* Not found */
+
+ /* First four bytes are our internal table of filesystems */
+ fsys = lookup_filesystem (*p);
+ if (fsys == MACH_PORT_NULL
+ || fsys_getfile (fsys, i->uids, i->nuids, i->gids, i->ngids,
+ (char *)(p + 1), NFS_FHSIZE - sizeof (int), &port))
+ {
+ mutex_unlock (&fhhashlock);
+ *cp = 0;
+ return p + NFS_FHSIZE / sizeof (int);
+ }
+
+ c = malloc (sizeof (struct cache_handle));
+ bcopy (p, c->handle, NFS_FHSIZE);
+ cred_ref (i);
+ c->ids = i;
+ c->port = port;
+ c->references = 1;
+
+ c->next = fhhashtable[hash];
+ if (c->next)
+ c->next->prevp = &c->next;
+ c->prevp = &fhhashtable[hash];
+ fhhashtable[hash] = c;
+
+ mutex_unlock (&fhhashlock);
+ *cp = c;
+ return p + NFS_FHSIZE / sizeof (int);
+}
+
+void
+cache_handle_rele (struct cache_handle *c)
+{
+ mutex_lock (&fhhashlock);
+ c->references--;
+ if (c->references == 0)
+ {
+ c->lastuse = mapped_time->seconds;
+ if (c->lastuse < leastfhlastuse || nfreefh == 0)
+ leastfhlastuse = c->lastuse;
+ nfreefh++;
+ }
+ mutex_unlock (&fhhashlock);
+}
+
+void
+scan_fhs ()
+{
+ struct cache_handle *c;
+ int n;
+ int newleast = mapped_time->seconds;
+
+ mutex_lock (&fhhashlock);
+ if (mapped_time->seconds - leastfhlastuse > FH_KEEP_TIMEOUT)
+ for (n = 0; n < FHHASH_TABLE_SIZE && nfreefh; n++)
+ for (c = fhhashtable[n]; c && nfreefh; c = c->next)
+ if (!c->references
+ && mapped_time->seconds - c->lastuse > FH_KEEP_TIMEOUT)
+ {
+ nfreefh--;
+ *c->prevp = c->next;
+ if (c->next)
+ c->next->prevp = c->prevp;
+ cred_rele (c->ids);
+ mach_port_deallocate (mach_task_self (), c->port);
+ free (c);
+ }
+ else
+ if (!c->references && newleast > c->lastuse)
+ newleast = c->lastuse;
+
+ /* If we didn't bail early, then this is valid. */
+ if (nfreefh)
+ leastfhlastuse = newleast;
+ mutex_unlock (&fhhashlock);
+}
+
+struct cache_handle *
+create_cached_handle (int fs, struct cache_handle *credc, file_t newport)
+{
+ char fhandle[NFS_FHSIZE];
+ error_t err;
+ struct cache_handle *c;
+ int hash;
+ char *bp = fhandle + sizeof (int);
+ size_t handlelen = NFS_FHSIZE - sizeof (int);
+
+ *(int *)fhandle = fs;
+ err = file_getfh (newport, &bp, &handlelen);
+ if (err || handlelen != NFS_FHSIZE - sizeof (int))
+ {
+ mach_port_deallocate (mach_task_self (), newport);
+ return 0;
+ }
+ if (bp != fhandle + sizeof (int))
+ {
+ bcopy (bp, fhandle + sizeof (int), NFS_FHSIZE - sizeof (int));
+ vm_deallocate (mach_task_self (), (vm_address_t) bp, handlelen);
+ }
+
+ hash = fh_hash (fhandle, credc->ids);
+ mutex_lock (&fhhashlock);
+ for (c = fhhashtable[hash]; c; c = c->next)
+ if (c->ids == credc->ids && ! bcmp (fhandle, c->handle, NFS_FHSIZE))
+ {
+ /* Return this one */
+ if (c->references == 0)
+ nfreefh--;
+ c->references++;
+ mutex_unlock (&fhhashlock);
+ mach_port_deallocate (mach_task_self (), newport);
+ return c;
+ }
+
+ /* Create it anew */
+ c = malloc (sizeof (struct cache_handle));
+ bcopy (fhandle, c->handle, NFS_FHSIZE);
+ cred_ref (credc->ids);
+ c->ids = credc->ids;
+ c->port = newport;
+ c->references = 1;
+
+ /* And add it to the hash table */
+ c->next = fhhashtable[hash];
+ if (c->next)
+ c->next->prevp = &c->next;
+ c->prevp = &fhhashtable[hash];
+ fhhashtable[hash] = c;
+ mutex_unlock (&fhhashlock);
+
+ return c;
+}
+
+
+
+static struct cached_reply *replyhashtable [REPLYHASH_TABLE_SIZE];
+static spin_lock_t replycachelock = SPIN_LOCK_INITIALIZER;
+static int nfreereplies;
+static int leastreplylastuse;
+
+/* Check the list of cached replies to see if this is a replay of a
+ previous transaction; if so, return the cache record. Otherwise,
+ create a new cache record. */
+struct cached_reply *
+check_cached_replies (int xid,
+ struct sockaddr_in *sender)
+{
+ struct cached_reply *cr;
+ int hash;
+
+ hash = xid % REPLYHASH_TABLE_SIZE;
+
+ spin_lock (&replycachelock);
+ for (cr = replyhashtable[hash]; cr; cr = cr->next)
+ if (cr->xid == xid
+ && !bcmp (sender, &cr->source, sizeof (struct sockaddr_in)))
+ {
+ cr->references++;
+ if (cr->references == 1)
+ nfreereplies--;
+ spin_unlock (&replycachelock);
+ mutex_lock (&cr->lock);
+ return cr;
+ }
+
+ cr = malloc (sizeof (struct cached_reply));
+ mutex_init (&cr->lock);
+ mutex_lock (&cr->lock);
+ bcopy (sender, &cr->source, sizeof (struct sockaddr_in));
+ cr->xid = xid;
+ cr->data = 0;
+
+ cr->next = replyhashtable[hash];
+ if (replyhashtable[hash])
+ replyhashtable[hash]->prevp = &cr->next;
+ cr->prevp = &replyhashtable[hash];
+ replyhashtable[hash] = cr;
+
+ spin_unlock (&replycachelock);
+ return cr;
+}
+
+/* A cached reply returned by check_cached_replies is now no longer
+ needed by its caller. */
+void
+release_cached_reply (struct cached_reply *cr)
+{
+ mutex_unlock (&cr->lock);
+ spin_lock (&replycachelock);
+ cr->references--;
+ if (cr->references == 0)
+ {
+ cr->lastuse = mapped_time->seconds;
+ if (cr->lastuse < leastreplylastuse || nfreereplies == 0)
+ leastreplylastuse = cr->lastuse;
+ nfreereplies++;
+ }
+ spin_unlock (&replycachelock);
+}
+
+void
+scan_replies ()
+{
+ struct cached_reply *cr;
+ int n;
+ int newleast = mapped_time->seconds;
+
+ spin_lock (&replycachelock);
+ if (mapped_time->seconds - leastreplylastuse > REPLY_KEEP_TIMEOUT)
+ for (n = 0; n < REPLYHASH_TABLE_SIZE && nfreereplies; n++)
+ for (cr = replyhashtable[n]; cr && nfreereplies; cr = cr->next)
+ if (!cr->references
+ && mapped_time->seconds - cr->lastuse > REPLY_KEEP_TIMEOUT)
+ {
+ nfreereplies--;
+ *cr->prevp = cr->next;
+ if (cr->next)
+ cr->next->prevp = cr->prevp;
+ if (cr->data)
+ free (cr->data);
+ }
+ else
+ if (!cr->references && newleast > cr->lastuse)
+ newleast = cr->lastuse;
+
+ /* If we didn't bail early, then this is valid */
+ if (nfreereplies)
+ leastreplylastuse = newleast;
+ spin_unlock (&replycachelock);
+}
diff --git a/nfsd/fsys.c b/nfsd/fsys.c
new file mode 100644
index 00000000..d3c50220
--- /dev/null
+++ b/nfsd/fsys.c
@@ -0,0 +1,192 @@
+/* Filesystem management for NFS server
+ Copyright (C) 1996 Free Software Foundation, Inc.
+ Written by Michael I. Bushnell, p/BSG.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#include <stdio.h>
+#include <errno.h>
+#include <hurd.h>
+#include <fcntl.h>
+#include <string.h>
+
+#include "nfsd.h"
+
+struct fsys_spec
+{
+ fsys_t fsys;
+ char *name;
+};
+
+static struct fsys_spec *fsystable;
+static int nfsys = 0;
+static int fsystablesize = 0;
+
+file_t index_file_dir;
+char *index_file_compname;
+
+/* Read the filesystem table in from disk */
+void
+init_filesystems (void)
+{
+ int nitems;
+ char *name;
+ int index;
+ int line;
+ file_t root;
+ static FILE *index_file;
+
+ fsystable = (struct fsys_spec *) malloc ((fsystablesize = 10)
+ * sizeof (struct fsys_spec));
+
+ if (!index_file_name)
+ return;
+
+ index_file = fopen (index_file_name, "r");
+ if (!index_file)
+ {
+ fprintf (stderr, "%s: Cannot open `%s': %s\n",
+ program_invocation_name, index_file_name, strerror (errno));
+ return;
+ }
+
+ for (line = 1; ; line++)
+ {
+ nitems = fscanf (index_file, "%d %as\n", &index, &name);
+ if (nitems == EOF)
+ {
+ fclose (index_file);
+ return;
+ }
+
+ if (nitems != 2)
+ {
+ fprintf (stderr, "%s:%s:%d Bad syntax\n",
+ program_invocation_name, index_file_name, line);
+ continue;
+ }
+
+ root = file_name_lookup (name, 0, 0);
+ if (!root)
+ {
+ fprintf (stderr, "%s:%s:%d Filesystem `%s': %s\n",
+ program_invocation_name, index_file_name, line,
+ name, strerror (errno));
+ free (name);
+ continue;
+ }
+
+ if (index >= fsystablesize)
+ fsystable = (struct fsys_spec *) realloc (fsystable,
+ (fsystablesize = index * 2)
+ * sizeof (struct fsys_spec));
+ if (index > nfsys)
+ nfsys = index;
+
+ fsystable[index].name = name;
+ file_getcontrol (root, &fsystable[nfsys].fsys);
+ mach_port_deallocate (mach_task_self (), root);
+ }
+}
+
+/* Write the current filesystem table to disk synchronously. */
+static void
+write_filesystems (void)
+{
+ file_t newindex;
+ FILE *f;
+ int i;
+
+ if (!index_file_name)
+ return;
+
+ if (index_file_dir == MACH_PORT_NULL)
+ {
+ index_file_dir = file_name_split (index_file_name, &index_file_compname);
+ if (index_file_dir == MACH_PORT_NULL)
+ {
+ fprintf (stderr, "%s: `%s': %s\n",
+ program_invocation_name, index_file_name, strerror (errno));
+ index_file_name = 0;
+ return;
+ }
+ }
+
+ /* Create an anonymous file in the same directory */
+ errno = dir_mkfile (index_file_dir, O_WRONLY, 0666, &newindex);
+ if (errno)
+ {
+ fprintf (stderr, "%s: `%s': %s\n",
+ program_invocation_name, index_file_name, strerror (errno));
+ index_file_name = 0;
+ mach_port_deallocate (mach_task_self (), index_file_dir);
+ index_file_dir = MACH_PORT_NULL;
+ return;
+ }
+
+ f = fopenport (newindex, "w");
+
+ for (i = 0; i < nfsys; i++)
+ if (fsystable[i].name)
+ fprintf (f, "%d %s\n", i, fsystable[i].name);
+
+ /* Link it in */
+ errno = dir_link (index_file_dir, newindex, index_file_compname, 0);
+ if (errno)
+ fprintf (stderr, "%s: `%s': %s\n",
+ program_invocation_name, index_file_name, strerror (errno));
+ fflush (f);
+ file_sync (newindex, 1, 0);
+ fclose (f);
+}
+
+/* From a filesystem ID number, return the fsys_t for talking to that
+ filesystem; MACH_PORT_NULL if it isn't in our list. */
+fsys_t
+lookup_filesystem (int id)
+{
+ if (id >= nfsys)
+ return MACH_PORT_NULL;
+ return fsystable[id].fsys;
+}
+
+/* Enter a name in the table of filesystems; return its ID number.
+ ROOT refers to the root of this filesystem. */
+int
+enter_filesystem (char *name, file_t root)
+{
+ int i;
+
+ for (i = 0; i < nfsys; i++)
+ if (fsystable[i].name && !strcmp (fsystable[i].name, name))
+ return i;
+
+ if (nfsys == fsystablesize)
+ fsystable = (struct fsys_spec *) realloc (fsystable,
+ (fsystablesize *= 2)
+ * sizeof (struct fsys_spec));
+
+ fsystable[nfsys].name = malloc (strlen (name) + 1);
+ strcpy (fsystable[nfsys].name, name);
+ file_getcontrol (root, &fsystable[nfsys].fsys);
+ nfsys++;
+
+ write_filesystems ();
+
+ return nfsys - 1;
+}
+
diff --git a/nfsd/loop.c b/nfsd/loop.c
new file mode 100644
index 00000000..3520e1da
--- /dev/null
+++ b/nfsd/loop.c
@@ -0,0 +1,233 @@
+/*
+ Copyright (C) 1996 Free Software Foundation, Inc.
+ Written by Michael I. Bushnell, p/BSG.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#include <string.h>
+#include <fcntl.h>
+
+#include "nfsd.h"
+
+#include <rpc/pmap_prot.h>
+#include "../nfs/rpcsvc/mount.h"
+
+#undef TRUE
+#undef FALSE
+#define malloc spoogie_woogie /* barf */
+#include <rpc/xdr.h>
+#include <rpc/types.h>
+#include <rpc/auth.h>
+#include <rpc/rpc_msg.h>
+#undef malloc
+
+void
+server_loop ()
+{
+ char buf[MAXIOSIZE];
+ int xid;
+ int *p, *r;
+ char *rbuf;
+ struct cached_reply *cr;
+ int program;
+ struct sockaddr_in sender;
+ int version;
+ int procedure;
+ struct proctable *table = 0;
+ struct procedure *proc;
+ struct idspec *cred;
+ struct cache_handle *c, fakec;
+ error_t err;
+ size_t addrlen;
+ fd_set readfds;
+ int maxfd;
+ int i;
+ int *errloc;
+
+ bzero (&fakec, sizeof (struct cache_handle));
+
+ if (main_udp_socket > pmap_udp_socket)
+ maxfd = main_udp_socket;
+ else
+ maxfd = pmap_udp_socket;
+
+ for (;;)
+ {
+ FD_ZERO (&readfds);
+ FD_SET (main_udp_socket, &readfds);
+ FD_SET (pmap_udp_socket, &readfds);
+ select (maxfd, &readfds, 0, 0, 0);
+
+ for (i = main_udp_socket;
+ i != -1;
+ i = (i == main_udp_socket ? pmap_udp_socket : -1))
+ {
+ if (!FD_ISSET (i, &readfds))
+ continue;
+
+ p = (int *) buf;
+ proc = 0;
+ addrlen = sizeof (struct sockaddr_in);
+ recvfrom (i, buf, MAXIOSIZE, 0, &sender, &addrlen);
+ xid = *p++;
+
+ /* Ignore things that aren't proper RPCs. */
+ if (ntohl (*p++) != CALL)
+ continue;
+
+ cr = check_cached_replies (xid, &sender);
+ if (cr->data)
+ /* This transacation has already completed */
+ goto repost_reply;
+
+ r = (int *) rbuf = malloc (MAXIOSIZE);
+
+ if (ntohl (*p++) != RPC_MSG_VERSION)
+ {
+ /* Reject RPC */
+ *r++ = xid;
+ *r++ = htonl (REPLY);
+ *r++ = htonl (MSG_DENIED);
+ *r++ = htonl (RPC_MISMATCH);
+ *r++ = htonl (RPC_MSG_VERSION);
+ *r++ = htonl (RPC_MSG_VERSION);
+ goto send_reply;
+ }
+
+ program = ntohl (*p++);
+ switch (program)
+ {
+ case MOUNTPROG:
+ version = MOUNTVERS;
+ table = &mounttable;
+ break;
+
+ case NFS_PROGRAM:
+ version = NFS_VERSION;
+ table = &nfstable;
+ break;
+
+ case PMAPPROG:
+ version = PMAPVERS;
+ table = &pmaptable;
+ break;
+
+ default:
+ /* Program unavailable */
+ *r++ = xid;
+ *r++ = htonl (REPLY);
+ *r++ = htonl (MSG_ACCEPTED);
+ *r++ = htonl (AUTH_NULL);
+ *r++ = htonl (0);
+ *r++ = htonl (PROG_UNAVAIL);
+ goto send_reply;
+ }
+
+ if (ntohl (*p++) != version)
+ {
+ /* Program mismatch */
+ *r++ = xid;
+ *r++ = htonl (REPLY);
+ *r++ = htonl (MSG_ACCEPTED);
+ *r++ = htonl (AUTH_NULL);
+ *r++ = htonl (0);
+ *r++ = htonl (PROG_MISMATCH);
+ *r++ = htonl (version);
+ *r++ = htonl (version);
+ goto send_reply;
+ }
+
+ procedure = htonl (*p++);
+ if (procedure < table->min
+ || procedure > table->max
+ || table->procs[procedure - table->min].func == 0)
+ {
+ /* Procedure unavailable */
+ *r++ = xid;
+ *r++ = htonl (REPLY);
+ *r++ = htonl (MSG_ACCEPTED);
+ *r++ = htonl (AUTH_NULL);
+ *r++ = htonl (0);
+ *r++ = htonl (PROC_UNAVAIL);
+ *r++ = htonl (table->min);
+ *r++ = htonl (table->max);
+ goto send_reply;
+ }
+ proc = &table->procs[procedure - table->min];
+
+ p = process_cred (p, &cred); /* auth */
+ p = skip_cred (p); /* verf */
+
+ if (proc->need_handle)
+ p = lookup_cache_handle (p, &c, cred);
+ else
+ {
+ fakec.ids = cred;
+ c = &fakec;
+ }
+
+ if (proc->alloc_reply)
+ {
+ size_t amt;
+ amt = (*proc->alloc_reply) (p) + 256;
+ if (amt > MAXIOSIZE)
+ {
+ free (rbuf);
+ r = (int *) rbuf = malloc (amt);
+ }
+ }
+
+ /* Fill in beginning of reply */
+ *r++ = xid;
+ *r++ = htonl (REPLY);
+ *r++ = htonl (MSG_ACCEPTED);
+ *r++ = htonl (AUTH_NULL);
+ *r++ = htonl (0);
+ *r++ = htonl (SUCCESS);
+ if (proc->process_error)
+ {
+ /* Assume success for now and patch it later if necessary */
+ errloc = r;
+ *r++ = htonl (0);
+ }
+
+ if (c)
+ err = (*proc->func) (c, p, &r);
+ else
+ err = ESTALE;
+
+ if (proc->process_error && err)
+ {
+ r = errloc;
+ *r++ = htonl (nfs_error_trans (err));
+ }
+
+ cred_rele (cred);
+ if (c != &fakec)
+ cache_handle_rele (c);
+
+ send_reply:
+ cr->data = rbuf;
+ cr->len = (char *)r - rbuf;
+
+ repost_reply:
+ sendto (i, cr->data, cr->len, 0,
+ (struct sockaddr *)&sender, addrlen);
+ release_cached_reply (cr);
+ }
+ }
+}
diff --git a/nfsd/main.c b/nfsd/main.c
new file mode 100644
index 00000000..69099361
--- /dev/null
+++ b/nfsd/main.c
@@ -0,0 +1,78 @@
+/* Main NFS server program
+ Copyright (C) 1996 Free Software Foundation, Inc.
+ Written by Michael I. Bushnell, p/BSG.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#include "nfsd.h"
+#include <stdio.h>
+#include <unistd.h>
+#include <rpc/pmap_prot.h>
+#include <maptime.h>
+
+int main_udp_socket, pmap_udp_socket;
+struct sockaddr_in main_address, pmap_address;
+char *index_file_name;
+
+int
+main (int argc, char **argv)
+{
+ int nthreads;
+
+ if (argc > 2)
+ {
+ fprintf (stderr, "%s [num-threads]\n", argv[0]);
+ exit (1);
+ }
+ if (argc == 1)
+ nthreads = 4;
+ else
+ nthreads = atoi (argv[1]);
+ if (!nthreads)
+ nthreads = 4;
+
+ index_file_name = asprintf ("%s/state/misc/nfsd.index", LOCALSTATEDIR);
+
+ maptime_map (0, 0, &mapped_time);
+
+ main_address.sin_family = AF_INET;
+ main_address.sin_port = htons (NFS_PORT);
+ main_address.sin_addr.s_addr = INADDR_ANY;
+ pmap_address.sin_family = AF_INET;
+ pmap_address.sin_port = htons (PMAPPORT);
+ pmap_address.sin_addr.s_addr = INADDR_ANY;
+
+ main_udp_socket = socket (PF_INET, SOCK_DGRAM, 0);
+ pmap_udp_socket = socket (PF_INET, SOCK_DGRAM, 0);
+ bind (main_udp_socket, (struct sockaddr *)&main_address,
+ sizeof (struct sockaddr_in));
+ bind (pmap_udp_socket, (struct sockaddr *)&pmap_address,
+ sizeof (struct sockaddr_in));
+
+ init_filesystems ();
+
+ while (nthreads--)
+ cthread_detach (cthread_fork ((cthread_fn_t) server_loop, 0));
+
+ for (;;)
+ {
+ sleep (1);
+ scan_fhs ();
+ scan_creds ();
+ scan_replies ();
+ }
+}
diff --git a/nfsd/nfsd.h b/nfsd/nfsd.h
new file mode 100644
index 00000000..7b6f530d
--- /dev/null
+++ b/nfsd/nfsd.h
@@ -0,0 +1,128 @@
+/*
+ Copyright (C) 1996 Free Software Foundation, Inc.
+ Written by Michael I. Bushnell, p/BSG.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+typedef int bool_t;
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <errno.h>
+#include <netinet/in.h>
+#include <cthreads.h>
+#include "../nfs/rpcsvc/nfs_prot.h" /* XXX */
+#include <hurd/fs.h>
+
+/* These should be configuration options */
+#define ID_KEEP_TIMEOUT 3600 /* one hour */
+#define FH_KEEP_TIMEOUT 600 /* ten minutes */
+#define REPLY_KEEP_TIMEOUT 120 /* two minutes */
+#define MAXIOSIZE 10240
+
+struct idspec
+{
+ struct idspec *next, **prevp;
+ int nuids, ngids;
+ uid_t *uids, *gids;
+ time_t lastuse;
+ int references;
+};
+
+struct cache_handle
+{
+ struct cache_handle *next, **prevp;
+ char handle[NFS_FHSIZE];
+ struct idspec *ids;
+ file_t port;
+ time_t lastuse;
+ int references;
+};
+
+struct cached_reply
+{
+ struct cached_reply *next, **prevp;
+ struct mutex lock;
+ struct sockaddr_in source;
+ int xid;
+ time_t lastuse;
+ int references;
+ size_t len;
+ char *data;
+};
+
+struct procedure
+{
+ error_t (*func) (struct cache_handle *, int *, int **);
+ size_t (*alloc_reply) (int *);
+ int need_handle;
+ int process_error;
+};
+
+struct proctable
+{
+ int min;
+ int max;
+ struct procedure procs[0];
+};
+
+volatile struct mapped_time_value *mapped_time;
+
+#define INTSIZE(n) (((n) + 3) >> 2)
+
+/* We don't actually distinguish between these two sockets, but
+ we have to listen on two different ports, so that's why they're here. */
+extern int main_udp_socket, pmap_udp_socket;
+extern struct sockaddr_in main_address, pmap_address;
+
+/* Name of the file on disk containing the filesystem index table */
+extern char *index_file_name;
+
+
+/* cache.c */
+int *process_cred (int *, struct idspec **);
+void cred_rele (struct idspec *);
+void cred_ref (struct idspec *);
+void scan_creds (void);
+int *lookup_cache_handle (int *, struct cache_handle **, struct idspec *);
+void cache_handle_rele (struct cache_handle *);
+void scan_fhs (void);
+struct cache_handle *create_cached_handle (int, struct cache_handle *, file_t);
+struct cached_reply *check_cached_replies (int, struct sockaddr_in *);
+void release_cached_reply (struct cached_reply *cr);
+void scan_replies (void);
+
+/* loop.c */
+void server_loop (void);
+
+/* ops.c */
+extern struct proctable nfstable, mounttable, pmaptable;
+
+/* xdr.c */
+int *skip_cred (int *);
+int nfs_error_trans (error_t);
+int *encode_fattr (int *, struct stat *);
+int *decode_name (int *, char **);
+int *encode_fhandle (int *, char *);
+int *encode_string (int *, char *);
+int *encode_data (int *, char *, size_t);
+int *encode_statfs (int *, struct statfs *);
+
+/* fsys.c */
+fsys_t lookup_filesystem (int);
+int enter_filesystem (char *, file_t);
+void init_filesystems (void);
diff --git a/nfsd/ops.c b/nfsd/ops.c
new file mode 100644
index 00000000..93c8373c
--- /dev/null
+++ b/nfsd/ops.c
@@ -0,0 +1,652 @@
+/* NFS daemon protocol operations
+ Copyright (C) 1996 Free Software Foundation, Inc.
+ Written by Michael I. Bushnell, p/BSG.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#include <hurd/io.h>
+#include <hurd/fs.h>
+#include <fcntl.h>
+#include <hurd/paths.h>
+#include <hurd.h>
+#include <dirent.h>
+
+#include "nfsd.h"
+#include "../nfs/rpcsvc/mount.h" /* XXX */
+#include <rpc/pmap_prot.h>
+
+static error_t
+op_null (struct cache_handle *c,
+ int *p,
+ int **reply)
+{
+ return 0;
+}
+
+static error_t
+op_getattr (struct cache_handle *c,
+ int *p,
+ int **reply)
+{
+ struct stat st;
+ error_t err;
+
+ err = io_stat (c->port, &st);
+ if (!err)
+ *reply = encode_fattr (*reply, &st);
+ return err;
+}
+
+static error_t
+complete_setattr (mach_port_t port,
+ int *p)
+{
+ uid_t uid, gid;
+ off_t size;
+ time_value_t atime, mtime;
+ struct stat st;
+ error_t err;
+
+ err = io_stat (port, &st);
+ if (err)
+ return err;
+
+ uid = ntohl (*p++);
+ gid = ntohl (*p++);
+ if ((uid != -1 && uid != st.st_uid)
+ || (gid != -1 && gid != st.st_gid))
+ {
+ if (uid == -1)
+ uid = st.st_uid;
+ if (gid == -1)
+ gid = st.st_gid;
+ err = file_chown (port, uid, gid);
+ if (err)
+ return err;
+ }
+
+ size = ntohl (*p++);
+ if (size != -1 && size != st.st_size)
+ err = file_set_size (port, size);
+ if (err)
+ return err;
+
+ atime.seconds = ntohl (*p++);
+ atime.microseconds = ntohl (*p++);
+ mtime.seconds = ntohl (*p++);
+ mtime.microseconds = ntohl (*p++);
+ if (atime.seconds != -1 && atime.microseconds == -1)
+ atime.microseconds = 0;
+ if (mtime.seconds != -1 && mtime.microseconds == -1)
+ mtime.microseconds = 0;
+ if (atime.seconds != -1 || mtime.seconds != -1
+ || atime.microseconds != -1 || mtime.microseconds != -1)
+ {
+ if (atime.seconds == -1)
+ atime.seconds = st.st_atime;
+ if (atime.microseconds == -1)
+ atime.microseconds = st.st_atime_usec;
+ if (mtime.seconds == -1)
+ mtime.seconds = st.st_mtime;
+ if (mtime.microseconds == -1)
+ mtime.microseconds = st.st_mtime_usec;
+ err = file_utimes (port, atime, mtime);
+ if (err)
+ return err;
+ }
+
+ return 0;
+}
+
+static error_t
+op_setattr (struct cache_handle *c,
+ int *p,
+ int **reply)
+{
+ error_t err = 0;
+ mode_t mode;
+
+ mode = ntohl (*p++);
+ if (mode != -1)
+ err = file_chmod (c->port, mode);
+ if (err)
+ return err;
+
+ return complete_setattr (c->port, p);
+}
+
+static error_t
+op_lookup (struct cache_handle *c,
+ int *p,
+ int **reply)
+{
+ error_t err;
+ char *name;
+ retry_type do_retry;
+ char retry_name [1024];
+ mach_port_t newport;
+ struct cache_handle *newc;
+ struct stat st;
+
+ decode_name (p, &name);
+
+ err = dir_lookup (c->port, name, O_NOTRANS, 0, &do_retry, retry_name,
+ &newport);
+ free (name);
+
+ /* Block attempts to bounce out of this filesystem by any technique */
+ if (!err
+ && (do_retry != FS_RETRY_NORMAL
+ || retry_name[0] != '\0'))
+ err = EACCES;
+
+ if (!err)
+ err = io_stat (newport, &st);
+
+ if (err)
+ return err;
+
+ newc = create_cached_handle (*(int *)c->handle, c, newport);
+ if (!newc)
+ return ESTALE;
+ *reply = encode_fhandle (*reply, newc->handle);
+ *reply = encode_fattr (*reply, &st);
+ return 0;
+}
+
+static error_t
+op_readlink (struct cache_handle *c,
+ int *p,
+ int **reply)
+{
+ char buf[2048], *transp = buf;
+ mach_msg_type_number_t len = sizeof (buf);
+ error_t err;
+
+ /* Shamelessly copied from the libc readlink */
+ err = file_get_translator (c->port, &transp, &len);
+ if (err)
+ return err;
+
+ if (len < sizeof (_HURD_SYMLINK)
+ || memcmp (transp, _HURD_SYMLINK, sizeof (_HURD_SYMLINK)))
+ return EINVAL;
+
+ transp += sizeof (_HURD_SYMLINK);
+
+ *reply = encode_string (*reply, transp);
+ return 0;
+}
+
+static size_t
+count_read_buffersize (int *p)
+{
+ return ntohl (*++p); /* skip OFFSET, return COUNT */
+}
+
+static error_t
+op_read (struct cache_handle *c,
+ int *p,
+ int **reply)
+{
+ off_t offset;
+ size_t count;
+ char buf[2048], *bp = buf;
+ mach_msg_type_number_t buflen = sizeof (buf);
+ struct stat st;
+ error_t err;
+
+ offset = ntohl (*p++);
+ count = ntohl (*p++);
+
+ err = io_read (c->port, &bp, &buflen, offset, count);
+ if (err)
+ return err;
+
+ err = io_stat (c->port, &st);
+ if (err)
+ return err;
+
+ *reply = encode_fattr (*reply, &st);
+ *reply = encode_data (*reply, bp, buflen);
+ return 0;
+}
+
+static error_t
+op_write (struct cache_handle *c,
+ int *p,
+ int **reply)
+{
+ off_t offset;
+ size_t count;
+ error_t err;
+ mach_msg_type_number_t amt;
+ char *bp;
+ struct stat st;
+
+ p++;
+ offset = ntohl (*p++);
+ p++;
+ count = ntohl (*p++);
+ bp = (char *) *reply;
+
+ while (count)
+ {
+ err = io_write (c->port, bp, count, offset, &amt);
+ if (err)
+ return err;
+ if (amt == 0)
+ return EIO;
+ count -= amt;
+ bp += amt;
+ offset += amt;
+ }
+
+ file_sync (c->port, 1, 0);
+
+ err = io_stat (c->port, &st);
+ if (err)
+ return err;
+ *reply = encode_fattr (*reply, &st);
+ return 0;
+}
+
+static error_t
+op_create (struct cache_handle *c,
+ int *p,
+ int **reply)
+{
+ error_t err;
+ char *name;
+ retry_type do_retry;
+ char retry_name [1024];
+ mach_port_t newport;
+ struct cache_handle *newc;
+ struct stat st;
+ mode_t mode;
+
+ p = decode_name (p, &name);
+ mode = ntohl (*p++);
+
+ err = dir_lookup (c->port, name, O_NOTRANS | O_CREAT | O_EXCL, mode,
+ &do_retry, retry_name, &newport);
+ if (!err
+ && (do_retry != FS_RETRY_NORMAL
+ || retry_name[0] != '\0'))
+ err = EACCES;
+
+ if (err)
+ return err;
+
+ err = complete_setattr (newport, p);
+ if (!err)
+ err = io_stat (newport, &st);
+
+ if (err)
+ {
+ dir_unlink (c->port, name);
+ free (name);
+ return err;
+ }
+ free (name);
+
+ newc = create_cached_handle (*(int *)c->handle, c, newport);
+ if (!newc)
+ return ESTALE;
+
+ *reply = encode_fhandle (*reply, newc->handle);
+ *reply = encode_fattr (*reply, &st);
+ return 0;
+}
+
+static error_t
+op_remove (struct cache_handle *c,
+ int *p,
+ int **reply)
+{
+ error_t err;
+ char *name;
+
+ decode_name (p, &name);
+
+ err = dir_unlink (c->port, name);
+ free (name);
+
+ return 0;
+}
+
+static error_t
+op_rename (struct cache_handle *fromc,
+ int *p,
+ int **reply)
+{
+ struct cache_handle *toc;
+ char *fromname, *toname;
+ error_t err = 0;
+
+ p = decode_name (p, &fromname);
+ p = lookup_cache_handle (p, &toc, fromc->ids);
+ decode_name (p, &toname);
+
+ if (!toc)
+ err = ESTALE;
+ if (!err)
+ err = dir_rename (fromc->port, fromname, toc->port, toname, 0);
+ free (fromname);
+ free (toname);
+ return err;
+}
+
+static error_t
+op_link (struct cache_handle *filec,
+ int *p,
+ int **reply)
+{
+ struct cache_handle *dirc;
+ char *name;
+ error_t err = 0;
+
+ p = lookup_cache_handle (p, &dirc, filec->ids);
+ decode_name (p, &name);
+
+ if (!dirc)
+ err = ESTALE;
+ if (!err)
+ err = dir_link (dirc->port, filec->port, name, 1);
+
+ free (name);
+ return err;
+}
+
+static error_t
+op_symlink (struct cache_handle *c,
+ int *p,
+ int **reply)
+{
+ char *name, *target;
+ error_t err;
+ mode_t mode;
+ file_t newport = MACH_PORT_NULL;
+ size_t len;
+ char *buf;
+
+ p = decode_name (p, &name);
+ p = decode_name (p, &target);
+ mode = ntohl (*p++);
+ if (mode == -1)
+ mode = 0777;
+
+ len = strlen (target) + 1;
+ buf = alloca (sizeof (_HURD_SYMLINK) + len);
+ memcpy (buf, _HURD_SYMLINK, sizeof (_HURD_SYMLINK));
+ memcpy (buf + sizeof (_HURD_SYMLINK), target, len);
+
+ err = dir_mkfile (c->port, O_WRITE, mode, &newport);
+ if (!err)
+ err = file_set_translator (newport,
+ FS_TRANS_EXCL|FS_TRANS_SET,
+ FS_TRANS_EXCL|FS_TRANS_SET, 0,
+ buf, sizeof (_HURD_SYMLINK) + len,
+ MACH_PORT_NULL, MACH_MSG_TYPE_COPY_SEND);
+ if (!err)
+ err = dir_link (c->port, newport, name, 1);
+
+ free (name);
+ free (target);
+
+ if (newport != MACH_PORT_NULL)
+ mach_port_deallocate (mach_task_self (), newport);
+ return err;
+}
+
+static error_t
+op_mkdir (struct cache_handle *c,
+ int *p,
+ int **reply)
+{
+ char *name;
+ mode_t mode;
+ retry_type do_retry;
+ char retry_name [1024];
+ mach_port_t newport;
+ struct stat st;
+ struct cache_handle *newc;
+ error_t err;
+
+ p = decode_name (p, &name);
+ mode = ntohl (*p++);
+
+ err = dir_mkdir (c->port, name, mode);
+
+ if (err)
+ {
+ free (name);
+ return err;
+ }
+
+ err = dir_lookup (c->port, name, O_NOTRANS, 0, &do_retry,
+ retry_name, &newport);
+ free (name);
+ if (!err
+ && (do_retry != FS_RETRY_NORMAL
+ || retry_name[0] != '\0'))
+ err = EACCES;
+ if (err)
+ return err;
+
+ err = complete_setattr (newport, p);
+ if (!err)
+ err = io_stat (newport, &st);
+ if (err)
+ return err;
+
+ newc = create_cached_handle (*(int *)c->handle, c, newport);
+ if (!newc)
+ return ESTALE;
+ *reply = encode_fhandle (*reply, newc->handle);
+ *reply = encode_fattr (*reply, &st);
+ return 0;
+}
+
+static error_t
+op_rmdir (struct cache_handle *c,
+ int *p,
+ int **reply)
+{
+ char *name;
+ error_t err;
+
+ decode_name (p, &name);
+
+ err = dir_rmdir (c->port, name);
+ free (name);
+ return err;
+}
+
+static error_t
+op_readdir (struct cache_handle *c,
+ int *p,
+ int **reply)
+{
+ int cookie;
+ unsigned count;
+ error_t err;
+ char *buf;
+ struct dirent *dp;
+ size_t bufsize;
+ int nentries;
+ int i;
+ int *replystart;
+
+ cookie = ntohl (*p++);
+ count = ntohl (*p++);
+
+ buf = alloca (count);
+ bufsize = count;
+ err = dir_readdir (c->port, &buf, &bufsize, cookie, -1, count, &nentries);
+ if (err)
+ return err;
+
+ if (nentries == 0)
+ {
+ *(*reply)++ = htonl (0); /* no entry */
+ *(*reply)++ = htonl (1); /* EOF */
+ }
+ else
+ {
+ for (i = 0, dp = (struct dirent *) buf, replystart = *reply;
+ ((char *)dp < buf + bufsize
+ && i < nentries
+ && (char *)reply < (char *)replystart + count);
+ i++, dp = (struct dirent *) ((char *)dp + dp->d_reclen))
+ {
+ *(*reply)++ = htonl (1); /* entry present */
+ *(*reply)++ = htonl (dp->d_ino);
+ *reply = encode_string (*reply, dp->d_name);
+ *(*reply)++ = htonl (i + cookie + 1); /* next entry */
+ }
+ *(*reply)++ = htonl (0); /* not EOF */
+ }
+
+ return 0;
+}
+
+static size_t
+count_readdir_buffersize (int *p)
+{
+ return ntohl (*++p); /* skip COOKIE; return COUNT */
+}
+
+static error_t
+op_statfs (struct cache_handle *c,
+ int *p,
+ int **reply)
+{
+ struct statfs st;
+ error_t err;
+
+ err = file_statfs (c->port, &st);
+ if (!err)
+ *reply = encode_statfs (*reply, &st);
+ return err;
+}
+
+static error_t
+op_mnt (struct cache_handle *c,
+ int *p,
+ int **reply)
+{
+ file_t root;
+ struct cache_handle *newc;
+ char *name;
+
+ decode_name (p, &name);
+
+ root = file_name_lookup (name, 0, 0);
+ if (!root)
+ {
+ free (name);
+ return errno;
+ }
+
+ newc = create_cached_handle (enter_filesystem (name, root), c, root);
+ free (name);
+ if (!newc)
+ return ESTALE;
+ *reply = encode_fhandle (*reply, newc->handle);
+ return 0;
+}
+
+static error_t
+op_getport (struct cache_handle *c,
+ int *p,
+ int **reply)
+{
+ int prog, vers, prot;
+
+ prog = ntohl (*p++);
+ vers = ntohl (*p++);
+ prot = ntohl (*p++);
+
+ if (prot != IPPROTO_UDP)
+ *(*reply)++ = htonl (0);
+ else if ((prog == MOUNTPROG && vers == MOUNTVERS)
+ || (prog == NFS_PROGRAM && vers == NFS_VERSION))
+ *(*reply)++ = htonl (NFS_PORT);
+ else if (prog == PMAPPROG && vers == PMAPVERS)
+ *(*reply)++ = htonl (PMAPPORT);
+ else
+ *(*reply)++ = 0;
+
+ return 0;
+}
+
+
+struct proctable nfstable =
+{
+ NFSPROC_NULL, /* first proc */
+ NFSPROC_STATFS, /* last proc */
+ {
+ { op_null, 0, 0, 0},
+ { op_getattr, 0, 1, 1},
+ { op_setattr, 0, 1, 1},
+ { 0, 0, 0, 0 }, /* deprecated NFSPROC_ROOT */
+ { op_lookup, 0, 1, 1},
+ { op_readlink, 0, 1, 1},
+ { op_read, count_read_buffersize, 1, 1},
+ { 0, 0, 0, 0 }, /* nonexistent NFSPROC_WRITECACHE */
+ { op_write, 0, 1, 1},
+ { op_create, 0, 1, 1},
+ { op_remove, 0, 1, 1},
+ { op_rename, 0, 1, 1},
+ { op_link, 0, 1, 1},
+ { op_symlink, 0, 1, 1},
+ { op_mkdir, 0, 1, 1},
+ { op_rmdir, 0, 1, 1},
+ { op_readdir, count_readdir_buffersize, 1, 1},
+ { op_statfs, 0, 1, 1},
+ }
+};
+
+
+struct proctable mounttable =
+{
+ MOUNTPROC_NULL, /* first proc */
+ MOUNTPROC_EXPORT, /* last proc */
+ {
+ { op_null, 0, 0, 0},
+ { op_mnt, 0, 0, 1},
+ { 0, 0, 0, 0}, /* MOUNTPROC_DUMP */
+ { 0, 0, 0, 0}, /* MOUNTPROC_UMNT */
+ { 0, 0, 0, 0}, /* MOUNTPROC_UMNTALL */
+ { 0, 0, 0, 0}, /* MOUNTPROC_EXPORT */
+ }
+};
+
+struct proctable pmaptable =
+{
+ PMAPPROC_NULL, /* first proc */
+ PMAPPROC_CALLIT, /* last proc */
+ {
+ { op_null, 0, 0, 0},
+ { 0, 0, 0, 0}, /* PMAPPROC_SET */
+ { 0, 0, 0, 0}, /* PMAPPROC_UNSET */
+ { op_getport, 0, 0, 0},
+ { 0, 0, 0, 0}, /* PMAPPROC_DUMP */
+ { 0, 0, 0, 0}, /* PMAPPROC_CALLIT */
+ }
+};
diff --git a/nfsd/proctables.c b/nfsd/proctables.c
new file mode 100644
index 00000000..1bc76a38
--- /dev/null
+++ b/nfsd/proctables.c
@@ -0,0 +1,57 @@
+/*
+ Copyright (C) 1996 Free Software Foundation, Inc.
+ Written by Michael I. Bushnell, p/BSG.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+
+struct proctable nfstable =
+{
+ NFSPROC_NULL, /* first proc */
+ NFSPROC_STATFS, /* last proc */
+ { op_null, 0, 0},
+ { op_getattr, 0, 1},
+ { op_setattr, 0, 1},
+ { 0, 0, 0 }, /* deprecated NFSPROC_ROOT */
+ { op_lookup, 0, 1},
+ { op_readlink, 0, 1},
+ { op_read, count_read_buffersize, 1},
+ { 0, 0, 0 }, /* nonexistent NFSPROC_WRITECACHE */
+ { op_write, 0, 1},
+ { op_create, 0, 1},
+ { op_remove, 0, 1},
+ { op_rename, 0, 1},
+ { op_link, 0, 1},
+ { op_symlink, 0, 1},
+ { op_mkdir, 0, 1},
+ { op_rmdir, 0, 1},
+ { op_readdir, count_readdir_buffersize, 1},
+ { op_statfs, 0, 1},
+};
+
+
+struct proctable mounttable =
+{
+ MOUNTPROC_NULL, /* first proc */
+ MOUNTPROC_EXPORT, /* last proc */
+ { op_null, 0, 0},
+ { op_mnt, 0, 0},
+ { 0, 0, 0}, /* MOUNTPROC_DUMP */
+ { 0, 0, 0}, /* MOUNTPROC_UMNT */
+ { 0, 0, 0}, /* MOUNTPROC_UMNTALL */
+ { 0, 0, 0}, /* MOUNTPROC_EXPORT */
+};
diff --git a/nfsd/xdr.c b/nfsd/xdr.c
new file mode 100644
index 00000000..d5bea0bd
--- /dev/null
+++ b/nfsd/xdr.c
@@ -0,0 +1,204 @@
+/* XDR packing and unpacking in nfsd
+ Copyright (C) 1996 Free Software Foundation, Inc.
+ Written by Michael I. Bushnell, p/BSG.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#include <sys/stat.h>
+#include <sys/statfs.h>
+#include <string.h>
+#include "nfsd.h"
+
+/* Return the address of the next thing after the credential at P. */
+int *
+skip_cred (int *p)
+{
+ int size;
+
+ p++; /* TYPE */
+ size = ntohl (*p++);
+ return p + INTSIZE (size);
+}
+
+/* Any better ideas? */
+static int
+hurd_mode_to_nfs_mode (mode_t m)
+{
+ return m & 0x177777;
+}
+
+static int
+hurd_mode_to_nfs_type (mode_t m)
+{
+ switch (m & S_IFMT)
+ {
+ case S_IFDIR:
+ return NFDIR;
+
+ case S_IFCHR:
+ return NFCHR;
+
+ case S_IFBLK:
+ return NFBLK;
+
+ case S_IFREG:
+ return NFREG;
+
+ case S_IFLNK:
+ return NFLNK;
+
+ case S_IFSOCK:
+ return NFSOCK;
+
+ case S_IFIFO:
+ return NFFIFO;
+
+ default:
+ return NFNON;
+ }
+}
+
+/* Encode ST into P and return the next thing to come after it. */
+int *
+encode_fattr (int *p, struct stat *st)
+{
+ *p++ = htonl (hurd_mode_to_nfs_type (st->st_mode));
+ *p++ = htonl (hurd_mode_to_nfs_mode (st->st_mode));
+ *p++ = htonl (st->st_nlink);
+ *p++ = htonl (st->st_uid);
+ *p++ = htonl (st->st_gid);
+ *p++ = htonl (st->st_size);
+ *p++ = htonl (st->st_blksize);
+ *p++ = htonl (st->st_rdev);
+ *p++ = htonl (st->st_blocks);
+ return p;
+}
+
+/* Decode P into NAME and return the next thing to come after it. */
+int *
+decode_name (int *p, char **name)
+{
+ int len;
+
+ len = ntohl (*p++);
+ *name = malloc (len + 1);
+ bcopy (p, *name, len);
+ (*name)[len] = '\0';
+ return p + INTSIZE (len);
+}
+
+/* Encode HANDLE into P and return the next thing to come after it. */
+int *
+encode_fhandle (int *p, char *handle)
+{
+ bcopy (handle, p, NFS_FHSIZE);
+ return p + INTSIZE (NFS_FHSIZE);
+}
+
+/* Encode STRING into P and return the next thing to come after it. */
+int *
+encode_string (int *p, char *string)
+{
+ return encode_data (p, string, strlen (string));
+}
+
+/* Encode DATA into P and return the next thing to come after it. */
+int *
+encode_data (int *p, char *data, size_t len)
+{
+ int nints = INTSIZE (len);
+
+ p[nints] = 0;
+ *p++ = htonl (len);
+ bcopy (data, p, len);
+ return p + nints;
+}
+
+/* Encode ST into P and return the next thing to come after it. */
+int *
+encode_statfs (int *p, struct statfs *st)
+{
+ *p++ = st->f_bsize;
+ *p++ = st->f_bsize;
+ *p++ = st->f_blocks;
+ *p++ = st->f_bfree;
+ *p++ = st->f_bavail;
+ return p;
+}
+
+/* Return an NFS error corresponding to Hurd error ERR. */
+int
+nfs_error_trans (error_t err)
+{
+ switch (err)
+ {
+ case 0:
+ return NFS_OK;
+
+ case EPERM:
+ return NFSERR_PERM;
+
+ case ENOENT:
+ return NFSERR_NOENT;
+
+ case EIO:
+ default:
+ return NFSERR_IO;
+
+ case ENXIO:
+ return NFSERR_NXIO;
+
+ case EACCES:
+ return NFSERR_ACCES;
+
+ case EEXIST:
+ return NFSERR_EXIST;
+
+ case ENODEV:
+ return NFSERR_NODEV;
+
+ case ENOTDIR:
+ return NFSERR_NOTDIR;
+
+ case EISDIR:
+ return NFSERR_ISDIR;
+
+ case E2BIG:
+ return NFSERR_FBIG;
+
+ case ENOSPC:
+ return NFSERR_NOSPC;
+
+ case EROFS:
+ return NFSERR_ROFS;
+
+ case ENAMETOOLONG:
+ return NFSERR_NAMETOOLONG;
+
+ case ENOTEMPTY:
+ return NFSERR_NOTEMPTY;
+
+ case EDQUOT:
+ return NFSERR_DQUOT;
+
+ case ESTALE:
+ return NFSERR_STALE;
+ }
+}
+
+
+
diff --git a/release/=announce-0.0 b/release/=announce-0.0
new file mode 100644
index 00000000..e9182c0c
--- /dev/null
+++ b/release/=announce-0.0
@@ -0,0 +1,67 @@
+I am pleased to announce version 0.0 of the GNU Hurd, available via
+anonymous FTP from prep.ai.mit.edu [18.159.0.42] in the file
+/pub/gnu/hurd-0.0.tar.gz (about XXX MB compressed).
+
+This file contains complete source code for the following:
+
+Hurd servers: auth, crash, devio, devport, exec, ext2fs, fifo, fwd,
+ifsock, init, magic, new-fifo, nfs, null, pfinet, pflocal, proc,
+symlink, term, ufs.
+
+Hurd libraries: diskfs, fshelp, ihash, iohelp, netfs, pager, pipe,
+ports, ps, shouldbeinlibc, store, threads, trivfs.
+
+Hurd utilities, etc: boot, shd, ps, settrans, showtrans, sync, su,
+mount, fsysopts, storeinfo, login, w, uptime, hurdids, loginpr, sush,
+vmstat, portinfo, devprobe, reboot, halt, fsck, fsck.ufs, mkfs.ufs,
+clri.ufs, stati.ufs, getty, rc.
+
+
+
+In addition, we have prepared a binary distribution of a complete
+version 0.0 GNU system corresponding to this Hurd release. This
+release runs only on PC-AT compatible systems with i[345]86
+processors.
+
+The GNU Hurd, plus MACH, is a kernel, not an operating system. The
+GNU operating system, like the Unix operating system, consists of many
+components, including kernel, libraries, compilers, assembler, shell,
+parser generators, utilities, window system, editors, text formatters,
+and so on. The GNU project set out a decade ago to develop this
+system, and we've been writing various components of it ever since.
+
+This release uses the `UK22' version of the Mach kernel, as
+distributed by the University of Utah. It is too difficult to prepare
+a detailed list of supported devices at this point. Common disk
+controllers and ethernet cards are surely supported.
+
+This release does not contain the X Window System.
+
+This release may be found by anonymous FTP from prep.ai.mit.edu
+[18.159.42] in the directory /pub/gnu/gnu-0.0/.
+
+In that directory, you should find the following files:
+
+grub-boot.image
+SOURCES
+INSTALL-binary
+gnu-0.0.tar.gz
+
+SOURCES contains a complete list describing the sources for the
+binaries found in the image. INSTALL-binary contains complete
+installation instructions for this release. gnu-0.0.tar.gz hold the
+image of complete system.
+
+grub-boot.image is an image of a floppy disk that you will need to
+complete part of the installation instructions.
+
+The following free software packages are found in this release:
+
+autoconf, automake, bash, bc, binutils, bison, cpio, cvs, diffutils,
+doschk, e2fsprogs, ed, emacs, fileutils, findutils, flex, from, gawk,
+gcal, gcc, gdb, gdbm, gettext, glibc, gmp, gperf, grep, grub, gzip,
+hello, hurd, indent, inetutils, less, mach, make, m4, miscfiles,
+ncurses, nvi, patch, ptx, rcs, readline, recode, sed, serverboot,
+sharutils, shellutils, tar, termcap, termutils, texinfo, textutils,
+time, wdiff.
+
diff --git a/release/COPYING.LIB b/release/COPYING.LIB
new file mode 100644
index 00000000..92b8903f
--- /dev/null
+++ b/release/COPYING.LIB
@@ -0,0 +1,481 @@
+ GNU LIBRARY GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1991 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 library GPL. It is
+ numbered 2 because it goes with version 2 of the ordinary GPL.]
+
+ 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 Library General Public License, applies to some
+specially designated Free Software Foundation software, and to any
+other libraries whose authors decide to use it. You can use it for
+your libraries, too.
+
+ When we speak of free software, we are referring to freedom, 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 or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the 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 a program 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.
+
+ Our method of protecting your rights has two steps: (1) copyright
+the library, and (2) offer you this license which gives you legal
+permission to copy, distribute and/or modify the library.
+
+ Also, for each distributor's protection, we want to make certain
+that everyone understands that there is no warranty for this free
+library. If the library is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original
+version, so that any problems introduced by others will not reflect on
+the original authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that companies distributing free
+software will individually obtain patent licenses, thus in effect
+transforming the program into proprietary software. To prevent this,
+we have made it clear that any patent must be licensed for everyone's
+free use or not licensed at all.
+
+ Most GNU software, including some libraries, is covered by the ordinary
+GNU General Public License, which was designed for utility programs. This
+license, the GNU Library General Public License, applies to certain
+designated libraries. This license is quite different from the ordinary
+one; be sure to read it in full, and don't assume that anything in it is
+the same as in the ordinary license.
+
+ The reason we have a separate public license for some libraries is that
+they blur the distinction we usually make between modifying or adding to a
+program and simply using it. Linking a program with a library, without
+changing the library, is in some sense simply using the library, and is
+analogous to running a utility program or application program. However, in
+a textual and legal sense, the linked executable is a combined work, a
+derivative of the original library, and the ordinary General Public License
+treats it as such.
+
+ Because of this blurred distinction, using the ordinary General
+Public License for libraries did not effectively promote software
+sharing, because most developers did not use the libraries. We
+concluded that weaker conditions might promote sharing better.
+
+ However, unrestricted linking of non-free programs would deprive the
+users of those programs of all benefit from the free status of the
+libraries themselves. This Library General Public License is intended to
+permit developers of non-free programs to use free libraries, while
+preserving your freedom as a user of such programs to change the free
+libraries that are incorporated in them. (We have not seen how to achieve
+this as regards changes in header files, but we have achieved it as regards
+changes in the actual functions of the Library.) The hope is that this
+will lead to faster development of free libraries.
+
+ 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, while the latter only
+works together with the library.
+
+ Note that it is possible for a library to be covered by the ordinary
+General Public License rather than by this special one.
+
+ GNU LIBRARY GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License Agreement applies to any software library which
+contains a notice placed by the copyright holder or other authorized
+party saying it may be distributed under the terms of this Library
+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 compile 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) 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.
+
+ c) 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.
+
+ d) 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 source code 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 to
+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 Library 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.
+
+ <one line to give the library's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the
+ library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+ <signature of Ty Coon>, 1 April 1990
+ Ty Coon, President of Vice
+
+That's all there is to it!
diff --git a/release/checklist b/release/checklist
new file mode 100644
index 00000000..4e0830a8
--- /dev/null
+++ b/release/checklist
@@ -0,0 +1,14 @@
+Checklist for Hurd releases.
+
+o Make sure /i486-gnu contains hard links, not copies.
+o Make sure we are using Hurd versions of su and uptime, not sh-utils.
+o Make install-dist from release dir.
+o Source code for Hurd and libc must be released.
+o Make sure everything listed in SOURCES is on prep.
+o Remove .stamp files from binary tree.
+o Make everything root.wheel, mode 755/644.
+o Check permissions on setuid files in binary tree.
+ (login, ps, w)
+o Check each directory for bogus cruft files.
+o Especially delete .bash_history, .gnunfs*, and .stamp files.
+o Verify installation on bare machine.
diff --git a/release/fstab-to-settrans b/release/fstab-to-settrans
new file mode 100755
index 00000000..e107cf10
--- /dev/null
+++ b/release/fstab-to-settrans
@@ -0,0 +1 @@
+sed -n 's;^\([^ ][^ ]*\)[ ][ ]*\([^ ][^ ]*\)[ ][ ]*nfs.*$;settrans -c \2 /hurd/nfs \1;p'
diff --git a/tasks b/tasks
new file mode 100644
index 00000000..7223e0f4
--- /dev/null
+++ b/tasks
@@ -0,0 +1,169 @@
+GNU Hurd Task List Version 1.15. Last updated 13 July 1996.
+
+If you would like to work on one of these, please contact
+mib@gnu.ai.mit.edu. It's important that you let me know what's being
+worked on, because someone else might also be interested, and you
+should coordinate work.
+
+Items that we want done with more priority are marked with !!!.
+
+
+
+General system work
+
+ * Compile all the free programs you can find to help us fix bugs in
+ the system, and to submit necessary ports to the maintainers of
+ those programs. A good place to start is the list in SOURCES under
+ the heading `Give up'.
+
+ * See how much of X compiles.
+
+ * Do whatever magic is necessary for Perl to take advantage of all
+ the nifty Hurd features that Unix doesn't have.
+
+
+
+Mach 3.0 Work
+
+If you plan to work on the microkernel, you should be on the mailing list
+for the University of Utah's Mach4 distribution; that is the microkernel
+distribution that GNU will use. To get on the mailing list, send mail to
+mach4-users-request@schirf.cs.utah.edu. You should discuss proposed
+microkernel work there as well as with mib@gnu.ai.mit.edu.
+
+!!!
+ * Mach 3.0 needs many new device drivers for popular PC devices.
+ Shantanu Goel at Utah is doing work in this area; coordinate with him.
+
+!!!
+ * A replacement for MiG that understood C .h files.
+ Utah is working on a new IDL compiler; coordinate with them.
+
+ * Bootstrap tools and documentation to help people set up Mach 3.0
+ machines if they already have Linux; if they already have Net BSD;
+ if they don't have anything. (See Utah Lites dist.)
+
+!!!
+ * Mach 3.0 needs to provide support for task virtual timers similar
+ in functionality to the Unix ITIMER_PROF and ITIMER_VIRTUAL timers.
+
+!!!
+ * Mach 3.0 needs to provide a way for users to do statistical PC
+ profiling similar to the Unix profil system call.
+
+!!!
+ * Mach 3.0 needs to make switches from MEMORY_OBJECT_COPY_DELAY to
+ MEMORY_OBJECT_COPY_NONE have the effect of immediately completing any
+ delayed copies.
+
+ * Mach 3.0 needs a facility to automatically send task and thread
+ status on task/thread exit to a port that can only be changed by
+ a privileged user; this would be used to implement process
+ accounting.
+
+ * Mach 3.0 needs a facility to find out what task is the parent of
+ a given task.
+
+ * Mach 3.0 needs a facility to find out which pages of a task's
+ address space are in core to implement Unix's mincore call.
+
+ * Mach 3.0 needs a facility to do msync.
+
+ * Utah Mach needs the OSF vm_remap call.
+
+ * Mach 3.0 needs a replacement for MEMORY_OBJECT_COPY_CALL that
+ works at least for the cases needed in ordinary files. (Write mib if
+ you want to know what the problem is and some ideas about how to
+ solve it.)
+
+!!!
+ * Mach 3.0 needs proxy memory objects. (mib can tell you what these
+ are and why they are important.)
+
+ * Mach 3.0 needs a way to do per-task resource counters that are
+ accessible to servers called by the task.
+
+ * Mach 3.0 should keep a timestamp of the creation of each task.
+
+ * Mach 3.0 needs facilities to implement resource limits of various sorts.
+
+ * Mach 3.0 needs a way to have a thread's CPU time statistics
+ include time spent by servers on its behalf. [This has been done
+ for the migrating-threads version of Mach; talk to mib before starting
+ work on it.]
+
+ * Of course, free ports are always necessary to machines that don't
+ already have free ports.
+
+ * Much work can be done doing research in how to improve Mach VM
+ performance and timesharing scheduling policy.
+
+!!!
+ * We need a good malloc for multi-threaded programs that uses
+ vm_allocate. It should probably be based on the current GNU malloc,
+ as well as merge the mmalloc interfaces used by some existing GNU
+ packages.
+
+ * Mach 3.0 needs facilities to get a list of all the devices which
+ can be device_open'd, as well as to get the type of a device.
+
+ * A way to have the kernel send a message on some designated port
+ everytime a new task is started.
+
+ * OSF has enhanced the exception_raise protocol to include thread_state
+ information. This code should be merged into the kernel; OSF people
+ have said their could could be released to the public (but it has not
+ appeared).
+
+ * Implement TASK_EVENTS_INFO.
+
+ * Add a timestamp for task and thread creation to the relevant info
+ structures (and make sure it works for the kernel task and threads).
+
+
+Hurd work (these are brief descriptions; mib can give more information):
+
+!!!
+ * An RPC trace program to aid debugging. Ask roland for more info.
+
+ * Programs that use utmp need to be changed to use /utmp and utmp.defs.
+
+ * We need some standard translators for /utmp nodes; most importantly
+ one for ordinary terminals (set up by login) and one for X displays
+ (set up by xdm).
+
+!!!
+ * We need some existing shell programs changed to do Hurd things:
+ like id, su, ls, tar, cpio, etc.
+
+ * Handy shell programs to send msgport msgs, and change default init
+ ports and ints.
+
+ * Shadow directory translators.
+
+ * A system for write, send, talkd and so forth to bleep users;
+ this should be integrated with the utmp replacement above.
+
+ * X. (Porting XFree86 should not be hard.)
+
+ * A filesystem for /tmp that uses virtual memory instead of disk.
+ (Roland has some ideas about this.)
+
+ * Filesystem implementations (using libdiskfs) for other popular
+ formats. Importantly, MSDOS FAT format.
+
+
+ * Transparent FTP translator.
+
+ * A fancy terminal driver that uses readline and supports detach/attach.
+
+ * A notepad program to hold and keep track of ports for shell scripts.
+
+
+
+C library work. See roland@gnu.ai.mit.edu if you are interested in working
+on anything in the C library.
+
+ * Useful response to SIGINFO.
+
+ * Better integration with cthreads.
diff --git a/utils/psout.h b/utils/psout.h
new file mode 100644
index 00000000..f9c44484
--- /dev/null
+++ b/utils/psout.h
@@ -0,0 +1,32 @@
+/* Common output function for ps & w
+
+ Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+
+ Written by Miles Bader <miles@gnu.ai.mit.edu>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifndef __PSOUT_H__
+#define __PSOUT_H__
+
+#include <ps.h>
+
+void psout (struct proc_stat_list *procs,
+ char *fmt_string, int posix_fmt, struct ps_fmt_specs *specs,
+ char *sort_key_name, int sort_reverse,
+ int output_width, int print_heading,
+ int squash_bogus_fields, int squash_nominal_fields);
+
+#endif /* __PSOUT_H__ */
diff --git a/utils/x.c b/utils/x.c
new file mode 100644
index 00000000..0e4f7e02
--- /dev/null
+++ b/utils/x.c
@@ -0,0 +1,248 @@
+/* Hurdish su
+
+ Copyright (C) 1996 Free Software Foundation, Inc.
+
+ Written by Miles Bader <miles@gnu.ai.mit.edu>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <hurd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <paths.h>
+#include <ctype.h>
+#include <utmp.h>
+#include <pwd.h>
+#include <grp.h>
+#include <netdb.h>
+#include <time.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <sys/fcntl.h>
+
+#include <argp.h>
+#include <argz.h>
+#include <envz.h>
+#include <idvec.h>
+#include <error.h>
+#include <timefmt.h>
+#include <hurd/lookup.h>
+
+static struct argp_option options[] =
+{
+ {"add", 'a', "USER", 0, "Add following ids"},
+ {"remove", 'r', "USER", 0, "Remove following ids"},
+ {"user", 'u', "USER", 0, "Add USER to the effective uids"},
+ {"avail-user",'U', "USER", 0, "Add USER to the available uids"},
+ {"group", 'g', "GROUP", 0, "Add GROUP to the effective groups"},
+ {"avail-group",'G',"GROUP", 0, "Add GROUP to the available groups"},
+ {0, 0}
+};
+static char *args_doc = "[USER...]";
+static char *doc =
+ "A USER specified as an argument adds (or removes) that user's groups as"
+ " well. When removing groups implied by such an argument, the groups to"
+ " which uids remaining in the process after any we remove are ignored."
+"\nUids and groups specified with options are used as-is.";
+
+/* Full set of desired authorization. XXX msg_del_auth doesn't allow such
+ fine control. */
+struct auth
+{
+ struct idvec euids, egids; /* Effective ids. */
+ struct idvec auids, agids; /* Available ids. */
+};
+
+/* Ids of our parent process, with the effect of this program being su'd
+ removed. */
+static struct idvec parent_uids = {0}, parent_gids = {0};
+
+/* Make sure that the parent_[ug]ids are filled in. To make them useful for
+ su'ing, each is the avail ids with all effective ids but the first
+ appended; this gets rid of the effect of login being suid, and is useful
+ as the new process's avail id list (e.g., the real id is right). */
+static void
+need_parent_ids ()
+{
+ if (parent_uids.num == 0 && parent_gids.num == 0)
+ {
+ struct idvec *p_eff_uids = make_idvec ();
+ struct idvec *p_eff_gids = make_idvec ();
+ if (!p_eff_uids || !p_eff_gids)
+ err = ENOMEM;
+ if (! err)
+ err = idvec_merge_auth (p_eff_uids, parent_uids,
+ p_eff_gids, parent_gids,
+ parent_auth);
+ if (! err)
+ {
+ idvec_delete (p_eff_uids, 0); /* Counteract setuid. */
+ idvec_delete (p_eff_gids, 0);
+ err = idvec_merge (parent_uids, p_eff_uids);
+ if (! err)
+ err = idvec_merge (parent_gids, p_eff_gids);
+ }
+ if (err)
+ error (39, err, "Can't get uids");
+ }
+}
+
+/* Returns true if the *caller* of this login program has UID. */
+static int
+parent_has_uid (uid_t uid)
+{
+ need_parent_ids ();
+ return idvec_contains (parent_uids, uid);
+}
+/* Returns true if the *caller* of this login program has GID. */
+static int
+parent_has_gid (gid_t gid)
+{
+ need_parent_ids ();
+ return idvec_contains (parent_gids, gid);
+}
+/* Returns the number of parent uids. */
+static int
+count_parent_uids ()
+{
+ need_parent_ids ();
+ return parent_uids.num;
+}
+/* Returns the number of parent gids. */
+static int
+count_parent_gids ()
+{
+ need_parent_ids ();
+ return parent_gids.num;
+}
+
+/* Make sure the user should be allowed to do this. */
+void verify_passwd (const char *name, const char *password,
+ uid_t id, int is_group, structh auth *auth)
+{
+ extern char *crypt (const char salt[2], const char *string);
+ char *prompt, *unencrypted, *encrypted;
+
+ if (!password || !*password
+ || idvec_contains (is_group ? auth->egids : auth->euids, id)
+ || idvec_contains (is_group ? auth->agids : auth->auids, id)
+ || (no_passwd
+ && (parent_has_uid (0)
+ || (is_group ? parent_has_uid (id) : parent_has_gid (id)))))
+ return; /* Already got this one. */
+
+ if (name)
+ asprintf (&prompt, "Password for %s%s:",
+ is_group ? "group " : "", name);
+ else
+ prompt = "Password:";
+
+ unencrypted = getpass (prompt);
+ encrypted = crypt (unencrypted, password);
+ /* Paranoia may destroya. */
+ memset (unencrypted, 0, strlen (unencrypted));
+
+ if (name)
+ free (prompt);
+
+ if (strcmp (encrypted, password) != 0)
+ error (50, 0, "Incorrect password", 0);
+}
+
+void
+main(int argc, char *argv[])
+{
+ int i;
+ error_t err = 0;
+ struct auth add, remove;
+
+ /* Parse our options... */
+ error_t parse_opt (int key, char *arg, struct argp_state *state)
+ {
+ switch (key)
+ {
+ case ARGP_KEY_NO_ARGS:
+ arg = "0"; /* root */
+ /* fall through. */
+
+ case 'u':
+ case 'U':
+ {
+ struct passwd *pw =
+ isdigit (*user) ? getpwuid (atoi (user)) : getpwnam (user);
+ /* True if this is the user arg and there were no user options. */
+
+ if (! pw)
+ error (10, 0, "%s: Unknown user", user);
+
+ verify_passwd (state->argv[state->next] ? pw->pw_name : 0,
+ pw->pw_passwd, pw->pw_uid, 0, &auth);
+
+ if (key == 'u')
+ idvec_add_new (&auth.euids, pw->pw_uid);
+ else if (key == 'U')
+ /* Add available ids instead of effective ones. */
+ idvec_add_new (&auth.auids, pw->pw_uid);
+ else
+ /* A plain argument. Add both the specified user and any
+ associated groups. */
+ {
+ /* Effective */
+ idvec_add_new (&auth.euids, 0, pw->pw_uid);
+ idvec_add_new (&auth.egids, 0, pw->pw_gid);
+ }
+ }
+ break;
+
+ case 'g':
+ case 'G':
+ {
+ struct group *gr =
+ isdigit (*arg) ? getgrgid (atoi (arg)) : getgrnam (arg);
+ if (! gr)
+ error (11, 0, "%s: Unknown group", arg);
+ verify_passwd (gr->gr_name, gr->gr_passwd, gr->gr_gid, 1, &auth);
+ idvec_add_new (key == 'g' ? &auth.egids : &auth.agids, gr->gr_gid);
+ }
+ break;
+
+ default:
+ return ARGP_ERR_UNKNOWN;
+ }
+ return 0;
+ }
+ struct argp argp = {options, parse_opt, args_doc, doc};
+
+ bzero (add, sizeof add);
+ bzero (remove, sizeof remove);
+
+
+ err =
+ auth_makeauth (getauth (), 0, MACH_MSG_TYPE_COPY_SEND, 0,
+ &auth.euids->ids, &auth.euids->num,
+ &auth.auids->ids, &auth.auids->num,
+ &auth.egids->ids, &auth.egids->num,
+ &auth.agids->ids, &auth.agids->num,
+ &auth);
+ if (err)
+ error (3, err, "Authentication failure", 0);
+
+
+ exit(0);
+}