From 94cef36797600d11a50d09828fa80df8a73dfd1c Mon Sep 17 00:00:00 2001 From: "Michael I. Bushnell" Date: Thu, 18 Jul 1996 04:35:29 +0000 Subject: *** empty log message *** --- BUGS | 33 ++ COPYING | 339 ++++++++++++++++++ INSTALL | 198 +++++++++++ INSTALL-cross | 119 +++++++ NEWS | 575 ++++++++++++++++++++++++++++++ README | 23 ++ SOURCES.0.0 | 196 ++++++++++ TODO | 227 ++++++++++++ boot/frank1.ld | 94 +++++ boot/frankemul.ld | 107 ++++++ exec/core.c | 264 ++++++++++++++ exec/elfcore.c | 100 ++++++ exec/exectrans.c | 81 +++++ exec/gcore.c | 88 +++++ hurd/=pending-changes | 26 ++ libfshelp/trans.h | 32 ++ libnetfs/execserver.h | 23 ++ libnetfs/file-exec.c | 164 +++++++++ libports/default-uninhibitable-rpcs.c | 27 ++ libports/import-port.c | 116 ++++++ libps/ps_msg.h | 633 +++++++++++++++++++++++++++++++++ libps/ps_term.h | 216 +++++++++++ libtreefs/Makefile | 40 +++ libtreefs/defhooks.c | 80 +++++ libtreefs/dir-hooks.c | 136 +++++++ libtreefs/dir-lookup.c | 305 ++++++++++++++++ libtreefs/fs-mutate.h | 30 ++ libtreefs/fsys-getroot.c | 144 ++++++++ libtreefs/fsys-hooks.c | 91 +++++ libtreefs/fsys-startup.c | 36 ++ libtreefs/fsys.c | 127 +++++++ libtreefs/hooks.c | 59 +++ libtreefs/mdir.c | 92 +++++ libtreefs/mig-decls.h | 41 +++ libtreefs/nlist.c | 70 ++++ libtreefs/node-hooks.c | 176 +++++++++ libtreefs/rights.c | 96 +++++ libtreefs/s-dir.c | 112 ++++++ libtreefs/s-file.c | 233 ++++++++++++ libtreefs/s-fsys.c | 77 ++++ libtreefs/s-io.c | 284 +++++++++++++++ libtreefs/trans-help.c | 129 +++++++ libtreefs/trans-start.c | 65 ++++ libtreefs/treefs-hooks.h | 401 +++++++++++++++++++++ libtreefs/treefs-s-hooks.h | 231 ++++++++++++ libtreefs/treefs.h | 472 ++++++++++++++++++++++++ mkinstalldirs | 40 +++ mount/mount.defs | 109 ++++++ mount/mount.h | 72 ++++ mount/mount_types.h | 61 ++++ nfs/pager.c | 448 +++++++++++++++++++++++ nfs/rpcsvc/mount.h | 81 +++++ nfs/rpcsvc/nfs_prot.h | 343 ++++++++++++++++++ nfsd/Makefile | 34 ++ nfsd/cache.c | 496 ++++++++++++++++++++++++++ nfsd/fsys.c | 192 ++++++++++ nfsd/loop.c | 233 ++++++++++++ nfsd/main.c | 78 ++++ nfsd/nfsd.h | 128 +++++++ nfsd/ops.c | 652 ++++++++++++++++++++++++++++++++++ nfsd/proctables.c | 57 +++ nfsd/xdr.c | 204 +++++++++++ release/=announce-0.0 | 67 ++++ release/COPYING.LIB | 481 +++++++++++++++++++++++++ release/checklist | 14 + release/fstab-to-settrans | 1 + tasks | 169 +++++++++ utils/psout.h | 32 ++ utils/x.c | 248 +++++++++++++ 69 files changed, 11448 insertions(+) create mode 100644 BUGS create mode 100644 COPYING create mode 100644 INSTALL create mode 100644 INSTALL-cross create mode 100644 NEWS create mode 100644 README create mode 100644 SOURCES.0.0 create mode 100644 TODO create mode 100644 boot/frank1.ld create mode 100644 boot/frankemul.ld create mode 100644 exec/core.c create mode 100644 exec/elfcore.c create mode 100644 exec/exectrans.c create mode 100644 exec/gcore.c create mode 100644 hurd/=pending-changes create mode 100644 libfshelp/trans.h create mode 100644 libnetfs/execserver.h create mode 100644 libnetfs/file-exec.c create mode 100644 libports/default-uninhibitable-rpcs.c create mode 100644 libports/import-port.c create mode 100644 libps/ps_msg.h create mode 100644 libps/ps_term.h create mode 100644 libtreefs/Makefile create mode 100644 libtreefs/defhooks.c create mode 100644 libtreefs/dir-hooks.c create mode 100644 libtreefs/dir-lookup.c create mode 100644 libtreefs/fs-mutate.h create mode 100644 libtreefs/fsys-getroot.c create mode 100644 libtreefs/fsys-hooks.c create mode 100644 libtreefs/fsys-startup.c create mode 100644 libtreefs/fsys.c create mode 100644 libtreefs/hooks.c create mode 100644 libtreefs/mdir.c create mode 100644 libtreefs/mig-decls.h create mode 100644 libtreefs/nlist.c create mode 100644 libtreefs/node-hooks.c create mode 100644 libtreefs/rights.c create mode 100644 libtreefs/s-dir.c create mode 100644 libtreefs/s-file.c create mode 100644 libtreefs/s-fsys.c create mode 100644 libtreefs/s-io.c create mode 100644 libtreefs/trans-help.c create mode 100644 libtreefs/trans-start.c create mode 100644 libtreefs/treefs-hooks.h create mode 100644 libtreefs/treefs-s-hooks.h create mode 100644 libtreefs/treefs.h create mode 100755 mkinstalldirs create mode 100644 mount/mount.defs create mode 100644 mount/mount.h create mode 100644 mount/mount_types.h create mode 100644 nfs/pager.c create mode 100644 nfs/rpcsvc/mount.h create mode 100644 nfs/rpcsvc/nfs_prot.h create mode 100644 nfsd/Makefile create mode 100644 nfsd/cache.c create mode 100644 nfsd/fsys.c create mode 100644 nfsd/loop.c create mode 100644 nfsd/main.c create mode 100644 nfsd/nfsd.h create mode 100644 nfsd/ops.c create mode 100644 nfsd/proctables.c create mode 100644 nfsd/xdr.c create mode 100644 release/=announce-0.0 create mode 100644 release/COPYING.LIB create mode 100644 release/checklist create mode 100755 release/fstab-to-settrans create mode 100644 tasks create mode 100644 utils/psout.h create mode 100644 utils/x.c 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. + + + Copyright (C) 19yy + + 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. + + , 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 /mig. ONLY. + +4. Do `make install' in /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 +#include "core_server.h" +#include +#include + +/* 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 +#include +#include +#include + +#include +#include + + +/* 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 +#include +#include +#include +#include + +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 +#include +#include +#include +#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 +#include +#include +#include +#include +#include + +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 + + 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 +#include +#include +#include + +/* 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 +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* 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 +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* 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 + + 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 + + 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 + +#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 +#include + +#include + +#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 + + 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 + +#include + +#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 + + 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 + + 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 + + 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 + + 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 + + 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 + + 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 + + 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 + + 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 + + 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 for more info + + Copyright (C) 1995 Free Software Foundation, Inc. + + Written by Miles Bader + + 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 for more info + + Copyright (C) 1995 Free Software Foundation, Inc. + + Written by Miles Bader + + 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 for more info + + Copyright (C) 1995 Free Software Foundation, Inc. + + Written by Miles Bader + + 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 for more info + + Copyright (C) 1995 Free Software Foundation, Inc. + + Written by Miles Bader + + 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 + + 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 + +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 + + 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 + + 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 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 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 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 + + 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 +#include +#include + +#include + +#include +#include +#include + +/* 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 +# 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 + + 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 + +subsystem mount 37000; + +import ; + +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 + + 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 + +#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 + + 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 +#include +#include +#include + +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 +#include +#include +#include +#include "nfsd.h" + + +#undef TRUE +#undef FALSE +#define malloc spoogie_woogie /* ugh^2. */ +#include +#include +#include +#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 +#include +#include +#include +#include + +#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 +#include + +#include "nfsd.h" + +#include +#include "../nfs/rpcsvc/mount.h" + +#undef TRUE +#undef FALSE +#define malloc spoogie_woogie /* barf */ +#include +#include +#include +#include +#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 +#include +#include +#include + +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 +#include +#include +#include +#include +#include "../nfs/rpcsvc/nfs_prot.h" /* XXX */ +#include + +/* 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 +#include +#include +#include +#include +#include + +#include "nfsd.h" +#include "../nfs/rpcsvc/mount.h" /* XXX */ +#include + +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 +#include +#include +#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. + + + Copyright (C) + + 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. + + , 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 + + 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 + +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 + + 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include + +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); +} -- cgit v1.2.3