? mydiff-072202.diff ? mydiff-072302.diff ? using_the_hurd.html Index: using_the_hurd.texi =================================================================== RCS file: /cvsroot/hurdextras/documentation/using_the_hurd.texi,v retrieving revision 1.4 diff -u -r1.4 using_the_hurd.texi --- using_the_hurd.texi 15 Jun 2002 22:35:10 -0000 1.4 +++ using_the_hurd.texi 23 Jul 2002 13:10:21 -0000 @@ -81,7 +81,7 @@ * Using:: Getting comfortable as a user. * Networking:: Getting connected. * Translators:: Extending the Hurd filesystem hierarchy. - +* Reference Manual:: Important Reference for the Programmer. @detailmenu --- The Detailed Node Listing --- @@ -94,7 +94,7 @@ * Copying:: The Hurd is free software. Installing -@c needs updating, will use Neal Walfield's Install Guide for Help. + * Binary Distributions:: Obtaining ready-to-run GNU distributions. * Archive Method:: Installing GNU from a current snapshot. * Cross-Compiling:: Building GNU from its source code. @@ -122,7 +122,6 @@ * Accessing the cdrom:: Getting to your data on cd. * Accessing the floppy:: Getting to your floppy disk. -@c not started yet. Networking * Configuring:: Configure your Network card. @@ -131,9 +130,6 @@ * Web Surfing:: Surfing the web in text mode. * Getting Your E-Mail:: How to get your e-mail -@c need intro to Lynx in Web Surfing -@c the basics is far from complete. - Translators * Invoking settrans:: Declaring how a node should be translated. @@ -141,6 +137,14 @@ * Invoking mount:: Unix-compatible active filesystem translators. * Invoking fsysopts:: Modifying translation parameters at runtime. +Foundations + +* Threads Library:: Every Hurd server and library is multithreaded. +* Ports Library:: Managing server port receive rights. +* Integer Hash Library:: Integer-keyed hash tables. +* Misc Library:: Things that soon will be in the GNU C library. +* Bug Address Library:: Where to report Hurd bugs. + @end detailmenu @end menu @@ -191,7 +195,7 @@ find the program's name in the index and go directly to the appropriate section. You may also wish to try running @kbd{@var{program} --help}, which will display a brief usage message for @var{program} -(@pxref{Foundations}). +. The rest of this manual is a guide to using the Hurd because it is not Unix. If you have never used a terminal or never touched GNU/Linux or @@ -200,8 +204,8 @@ This manual is organized in a way that a user can get comfortable with using the Hurd. If you already have the machine up and running you can -skip right to the user-land chapter or the networking chapter and get -connected to the rest of the world. +skip right to the (@pxref{Using}) chapter or the (@pxref{Networking}) +chapter and get connected to the rest of the world. @node Features @comment node, Next, Prev, Up @@ -322,6 +326,29 @@ [Gnusletter, Nov. 1991], the Hurd (running on Mach) is GNU's official kernel. +@node Hurd Today +@comment node, Next, Prev, Up +@section Hurd Today + +The GNU operating system is alive and well today. In 1998 Marcus Brinkmann +brought the Hurd to the Debian Project. This allowed the Hurd +to have a software management system(apt and dpkg), world wide access +to the latest free software, and a extreme increase of popularity. + +The original architect Thomas Bushnell BSG is involved on the mailing lists +helping the young hackers design and help with Hurd development. There is +now a team of individuals from around the world. They are constantly giving +talks at conferences about the importance of design and implementation of +the Hurds unique multiserver microkernel enviroment. There is also work +on porting the Hurd to two other micro-kernels and another architecture. + +So far Debian GNU/Hurd has been the most active non-Linux port. The user +applications that are ported to the Hurd are the latest and are actively +being improved. Development of the Hurd within the Debian project has also +contributed to incremental development releases on compact-disk. Also +a new developer is allowed to get the source code to the Hurd from anywhere +on the planet. A developer can even get a more recent snapshot release from +the the GNU projects alpha ftp server. @node Copying @comment node, next, prev, up @@ -338,7 +365,7 @@ on Intel i386-compatible architectures (such as the Pentium), using the GNU Mach micro-kernel. -If you have unsupported hardware or a different micro-kernel, you will +If you have unsupported hardware or a different microkernel, you will not be able to run the Hurd until all the required software has been @dfn{ported} to your architecture. Porting is an involved process which requires considerable programming skills, and is not recommended for the @@ -423,7 +450,7 @@ @example bash-2.05# mke2fs -o hurd /dev/hda3 @end example -@c This is the old way I need to update my brain + After this is done you can mount the partition and extract your archived snapshot into that directory. @@ -433,9 +460,20 @@ bash-2.05# tar zxvpf ~/gnu-latest.tar.gz @end example -After your done you should be able to reboot.The grub boot disk is need to +After your done you should be able to reboot.The grub boot disk is needed to boot the Hurd. Once your booted you can finish the installation by -running the native-install file. +running the native-install file.@emph{I have to note that when you are booting +the Hurd for the first time you must give Grub the single-user option (-s) +like in the following example. Also note that the first long module entry is +all on one line. } + +@display +title GNU/Hurd +root (hd0,0) +kernel /boot/gnumach.gz -s root=device:hd0s1 +module /hurd/ext2fs.static --multiboot-command-line=$@{kernel-command-line@} --host-priv-port=$@{host-port@} --device-master-port=$@{device-port@} --exec-server-task=$@{exec-task@} -T typed $@{root@} $(task-create) $(task-resume) +module /lib/ld.so.1 /hurd/exec $(exec-task=task-create) +@end display @node Cross-Compiling @section Cross-Compiling @@ -477,7 +515,7 @@ legend about a boy who was able to fly by pulling himself up by his bootstraps. In computers, this term refers to any process where a simple system activates a more complicated system.} is the procedure by -which your machine loads the micro-kernel and transfers control to the +which your machine loads the microkernel and transfers control to the Hurd servers. @menu @@ -519,6 +557,110 @@ good idea to do regularly because of the unreliability of the floppy disk. In this section I will show you how to install GRUB into the master boot record of your hard-disk. + What you need are: +@enumerate +@item +Grub boot floppy. +@item +Grub installed onto Hard-disk. +@item +Knowledge of where you installed GNU/Hurd. +@end enumerate + +First you will need to make a directory for grub. Do this now(You must be logged +in as root). + +@example +bash-2.05#mkdir /boot/grub +@end example + +Now you must copy the contents of the grub installed loader files.These are +usually located in /lib/grub/i386-unknown-pc/.All the files in this directory +need to be copied to the boot directory. + +@example +bash-2.05#cp /lib/grub/i386-unknown-pc/* /boot/grub/ +@end example + +Now you have two more things to do. Next you have to construct a menu.lst file +to put in your /boot/grub directory. This file is the file that displays a +menu at boot time. Before you tackle this you should read the grub info pages +to get a better understanding of the way grub works. The reason I ask this of you +is that the Hurd is constantly being worked on to boot more effiecently and +the syntax may change with the Hurd's development releases. + +This is my sample menu.lst file + +@display +timeout 10 + +color light-grey/black red/light-grey + +title GNU/Hurd +root (hd0,0) +kernel /boot/gnumach.gz root=device:hd0s1 +module /hurd/ext2fs.static --multiboot-command-line=$@{kernel-command-line@} --host-priv-port=$@{host-port@} --device-master-port=$@{device-port@} --exec-server-task=$@{exec-task@} -T typed $@{root@} $(task-create) $(task-resume) +module /lib/ld.so.1 /hurd/exec $(exec-task=task-create) + +title Debian GNU/Linux +root (hd0,1) +kernel /vmlinuz root=/dev/hda2 ro +@end display + +Now that you have your menu.lst file in /boot/grub you are ready to install +the grub and make your machine bootable from the hard-disk. You should write +down what you wrote in your menu.lst file. You need this information to type +into the grub command line. If you forget your grub boot floppy should be +able to boot your system so you can write that data down and continue with the +installation of grub. + +When you get to your boot menu of the floppy press C. The C will put you at +the Grub command prompt. You need to start with the root command. + +@example +:grub>root (hd0,0) +@end example + +My GNU/Hurd is installed on the first partition of the first drive.Thats what +the above example is telling Grub. After you press enter it should print out +something along the lines as <ext2 and a bunch of numbers>. This means it found +your filesytem that wants to be the root. Next you need Grub to load the kernel. +This is the tricky part.Heres what I have. + +@example +:grub>kernel /boot/gnumach.gz root=device:hd0s1 +@end example + +Once you press enter again you'll see some more info. If you get an error that +just means you either typed wrong or you picked the wrong root device for Grub. + +Next you need to enter the modules for Grub to use. This is probably the trickiest +part of booting the rest of the Hurd. + +@display +:grub>module /hurd/ext2fs.static --multiboot-command-line=$@{kernel-command-line@} --host-priv-port=$@{host-port@} --device-master-port=$@{device-port@} --exec-server-task=$@{exec-task@} -T typed $@{root@} $(task-create) $(task-resume) +@end display +@emph{Note this should be all on one line no <enter> until the end.} + +@example +:grub>module /lib/ld.so.1 /hurd/exec $(exec-task=task-create) +@end example + +To fully understand these two module commands you can check the Hurd Reference +Manual. That manual should explain every detail. These are very important for +developers they can do many things with the Grub bootloader and the Hurd. + +As soon as you start updating your system(rebuilding kernels,Hurd servers) the +Grub menus will get more complex. After this command if your still with me +(if not read the Grub docs)you can safely install with. + +@example +:grub>setup (hd0) +@end example + +If this is successful you should be able to press the reset button and remove +the Grub floppy. You just installed Grub to the master boot record of the hard +disk this alone is something many men and women dare not tread. @node Server Bootstrap @section Server Bootstrap @@ -679,9 +821,9 @@ @end enumerate Note that it is impossible to share microkernel devices between the two -running Hurds, so don't get any funny ideas. When you're finished -testing your new Hurd, then you can run the @code{halt} or @code{reboot} -programs to return control to the parent Hurd. +running Hurds, so don't get confused with which one your testing. When +you're finished testing your new Hurd, then you can run the @code{halt} +or @code{reboot} programs to return control to the parent Hurd. @c FIXME: the `don't get any funny ideas' comment is confusing. Am @c I genuinely in some sort of danger if I contemplate sharing @@ -748,7 +890,17 @@ @scindex halt @scindex reboot -FIXME: finish +You can shut down or reboot your hurd machine by typing these commands. +@example +bash-2.05# reboot +@end example + +@example +bash-2.05# halt +@end example +In a matter of seconds it should tell you that it is in a type loop and +pressing control, alt, and delete at the same time will make the Hurd +reboot. @node Using @comment node, next, prev, up @@ -785,13 +937,13 @@ your computer. I am not going to cover it here but I'll give you a tip.In Nano Control and a letter are what gets you to open,edit and save files. - This section hopes to get you started with these necessity commands. +This section hopes to get you started with these necessity commands. If you have knowledge of these already you can probably skip ahead. Also you might want to get comfortable with the default editor first then come back to this section to learn your basic GNU/Hurd shell commands. The shell is the the program that interacts with the file system and the data -on the file system. This is called bash(bourne again shell). Once you get +on the file system. This is called bash(Bourne again shell). Once you get comfortable with the shell you can happily sit at any Unix-Like workstation and get some work done. It is very important that you get comfortable with the shell. It is also called terminal,console, etc.At this prompt you should be @@ -822,7 +974,6 @@ There is another short cut, cd ../ This puts you in the directory above the one your in. - To view a file there are many ways,but we'll use the most common command called cat. @@ -897,7 +1048,7 @@ bash-2.05$ rm README <ENTER> @end example -Now rm with some options +Now rm with some options. @example bash-2.05$ rm -rf foo2/ file1.txt <ENTER> @@ -935,6 +1086,7 @@ @node More Basics @comment node, next, prev, up @section More Basics +@c I need to add bzip2 and gzip compressing commands and example In this section I want the user to learn some extra things to make life interesting. You will need to learn about archives. Archives come in @@ -951,16 +1103,24 @@ Lets say we get a tar file that has some documents you want to read. Make sure your in your home directory when you try. @example -bash-2.05$ tar xv docs.tar +bash-2.05$ tar xv docs.tar <ENTER> @end example After running this command you would see the contents of the tar file extracted to your home directory.The x stands for extract and v means verbose which shows -us the contents of the archive as it's being decompressed. +us the contents of the archive as it's being decompressed. Compressing a file +or directory is very simliar. You would use this. +@example +bash-2.05$ tar -cv new.tar foo1/ foo2/ <ENTER> +@end example +The -c is to create the tar file. We add the name of the tar file then the +contents we want. In the previous example we created a file called new.tar +and we added the directories foo1/ and foo2/ to the tar file. With the -v +option we see what is being added. The next most common archive file is the gzip format.Files with .gz are associated with gzip.These utlities work so well together that people have patched the -tar command so that it can compress and decompress gzip files.If you file has no +tar command so that it can compress and decompress gzip files.If your file has no .tar in the file name and only .gz at the end you cannot use tar. @example @@ -981,7 +1141,49 @@ bash-2.05$ gunzip file.gz <ENTER> @end example +To compress tar files or any file using gzip you would use this: +@example +bash-2.05$ gzip -9 file.tar <ENTER> +@end example +The -9 means best compression. There are many options available for gzip.A +quick browse through the info pages will tell you everything you need. + +Another common archiving example is the bzip2 format. The bzip2 format is usually +see as .tar.bz2. This format is known to be one of the best compression utilities. +To extract a bzip2 file you would use. + +@example +bash-2.05$ bunzip2 file.bz2 <ENTER> +@end example + + +Like the gzip format the bzip2 format has many options. You will probably see +bzip2 compressing tar files. The bzip2 utility actually has a lot of other +commands linked to it. To extract a file thats been compressed with tar and +bzip2 you would use the following example. + +@example +bash-2.05$ bzcat file.tar.bz2 |tar -xv <ENTER> +@end example + +The bzcat command is a combination of bunzip2 and cat. We bzcat the file then +pipe(|)the file to the tar command. Once again I use -x to extract the file +and -v to see it's contents. To compress a file using bzip2 you would use: +@example +bash-2.05$ bzip2 -z file1.txt <ENTER> +@end example +This command makes file1.txt end up looking like file1.txt.bz2 and slightly +smaller. You can also use the '-9' option for best compression. + +Hopefully this little chapter has gotten you more interested in using the Hurd. +If you are still confused please read the info pages for the command your +confused on. The command @code{info} will give you a list of all the programs +on your Hurd machine that have documentation with them. The best way to learn +GNU utilities is to read and practice. The Hurd is just like music, you can +never learn enough. This chapter is mean to give you a stepping stone to freedom. + + @node Administration @comment node, next, prev, up @section Administration @@ -990,7 +1192,7 @@ is so fond of. The Hurd is trying to get all things root out of the picture. They want you the user to be able to do things that you can't on a traditional Unix- like operating system. For the time being you will have to deal with the root -user. One reasonable request of the Unix type gurus is makeing a normal user +user. One reasonable request of the Unix type gurus is making a normal user (unpriveledged to write anywhere on the filesystem besides the user's home directory). The reasoning behind this is that you a normal user can not mess up your computer. This is a decent compromise because the more we explore and @@ -998,43 +1200,30 @@ what we'll do is set up a user account for you. You have to be root to do this. @example -bash-2.05# adduser user <ENTER> - +bash-2.05# adduser <ENTER> @end example -That's it! The computer will prompt you for a username then you can just answer -yes or whatever you require to the rest of the requests. - -To set a password on that accont you just created you would type: +That's it! The computer will prompt you for a user-name and password then you +can just answer yes or whatever you require to the rest of the requests. +To change the password on your account you just created you would type: @example -bash-2.05# passwd <USER_NAME> +bash-2.05# passwd <USER_NAME> <ENTER> Please Enter a Password: @end example There is a command that helps you become root from a normal user account. This command is called su. When you type su you are required to enter a password -(if you have one) for the root. +(if you have one) for the root.This command works the other way also for +instance if a ssh(Secure Shell) server doesn't allow root you can su to a +user that has an account on that server. @example -bash-2.05$su +bash-2.05$ su <ENTER> password: @end example -Another important command for the administrator is to shutdown the computer. -This is done with a few different commands. I'll give you the basics and you -can go from there. - -@example -bash-2.05#halt <ENTER> -bash-2.05#shutdown -h now <ENTER> -@end example - -Both of these commands do pretty much the same thing.There are many options -for shutting down the system.I'm pretty sure these will be all you need for -now. - There are a lot of commands related to the Administering unix-like operating -systems. As a normal user a lot is uneeded. Makeing a new user and giving +systems. As a normal user a lot is unneeded. Making a new user and giving him/her a password is enough for now.If you are interested in becoming a Administrator there are plenty of books and classes out there. @@ -1043,12 +1232,12 @@ @section Accessing the cdrom On the Hurd we don't mount anything.Mount is a Unix command.The Hurd has a -similiar mechanism to accessing devices.We use the settrans command to do -this. settrans is a program that aligns a Hurd Server(or translator) to -a device supported by the kernel.For instance on my GNU/Hurd system my -cdrom device was detected as hd2. To get to my data on a iso9660 cdrom - I first had to make the device. Then I had to run the settrans command -.This had to be done as the root user(root is the only +similar mechanism to accessing devices called "setting a translator".We use + the settrans command to do this. Settrans is a program that aligns a +Hurd Server(or translator) to a device supported by the kernel.For instance +on my GNU/Hurd system my cdrom device was detected as hd2. To get to my data +on a iso9660 cdrom I first had to make the device. Then I had to run the +settrans command. This had to be done as the root user(root is the only user that has these privileges). @example @@ -1094,7 +1283,7 @@ * Accessing FTP:: Using the FTP protocol. * Accessing NFS:: Using the NFS protocol. * Web Surfing:: Surfing the web in text mode. -* Getting Your E-Mail:: How to get your e-mail + @end menu @node Configuring @@ -1138,8 +1327,8 @@ nameserver xxx.xxx.xxx.xxx #ip addresses of your isp's nameservers(aka DNS servers) @end example -After this is all set up you should be able to ping any host on the internet -snd recieve a response.The next file to setup is the /etc/hosts file. This +After this is all set up you should be able to ping any host on the Internet +and recieve a response.The next file to setup is the /etc/hosts file. This file is used for machines you access frequently. Instead if typing ip addresses for computers on your network you edit /etc/hosts to allow you to just type the name of the computer you want to access. @@ -1153,10 +1342,124 @@ Now I can access 192.168.1.5 by simply using its name jojo. The same is true with mojo also. For instance if I wanted to telnet into one of those machines I would -type telnet jojo(With the proliferation of mischief on the internet it is +type telnet jojo(With the proliferation of mischief on the Internet it is recommended you use the OpenSSH suite to access remote computers). +@node Accessing FTP +@comment node, next, prev, up +@section Accessing FTP + +FTP stands for File Transfer Protocol. This protocol has been around since +the beginnings of GNU and Unix. It is a easy and fast way of sending files +to friends, family, and colleagues. The Hurd has two methods of using ftp. +One is setting a translator with the Hurds ftpfs server. The other way is +the traditional client server method where you login and use get and put +commands. + +The ftpfs translator is quite unique. It allows the user to have a remote +ftp server accessible on a local directory. You the user would then begin +copying files like it was just another directory. + +@example +$bash-2.05#settrans -ac /mnt /hurd/ftpfs / alpha.gnu.org +@end example + +This command will set a translator for ftpfs. What happens is the ftpfs translator +places the root directory of alpha.gnu.org's anonymous ftp server on the /mnt +directory. Now one can access the data like is was a local filesystem. + +In the traditional matter the FTP protocol is accessed using a client. +Typical console based clients are the ones that come with the inet-utils package +(The Hurds native ftp client,ncftp, and many others). The traditional method of +ftp is pretty much a standard for Unix-like operating systems. If you learn this +method you should be able to comfortably sit at any Unix-like workstation and +send and retrieve files. I will give you a start but their are many more options +so read the info pages for some more complex operations. + +@example +bash-2.05:$ftp <ENTER> +ftp>open ftp.gnu.org +@end example + +You should then be prompted for a user-name and password.You can login to +servers on the Internet who offer anonymous ftp access. A anonymous ftp +server is a server that allows anyone access to it's files. You would +simply type anonymous at the user prompt then type your e-mail address as +the password. + +The standard commands that are used are.@code{get},@code{put},@code{mget}, +@code{mput},@code{ls},@code{pwd},and @code{cd}. These will work with any +standard ftp client.The commands themselves are self explanatory. The +@code{mget} and @code{mput} are for multiple files. An example would be. + +@example +ftp> mget *.tar.gz +@end example + +This would try to download any files in the current directory with a .tar.gz +extensions. Don't worry if you say mget instead of get by accident because +it will prompt you at every file. It will allow you to say yes,no,all,abort and +quit. The ftp protocol and applications are fairly simple to pick up, you just +have to practice. Trying it a handful of times will get you very familiar, quickly. + +@node Accessing NFS +@comment node, next, prev, up +@section Acessing NFS + +The NFS protocol is a standard method for sharing files between Unix-like +workstations.The server allocates directories that it wants sharable through +exporting.Traditionally the workstation would mount the shared directory +onto the local file system. + +For instance, Server1's /etc/exports file it says: + +/usr/src mojo(rw,insecure) + +This would allow the workstation known as mojo read and write access to the +/usr/src directory. The workstation would then type mount Server1:/usr/src /mnt. +The workstation(mojo) can ls /mnt and see all the files in Server1's /usr/src +directory.(Note: The /etc/hosts file on both server and workstation should have +appropriate ip address' for things to work.) + +On the Hurd we access a network share by setting the nfs translator. This is +done like this: + +@example +bash-2.05# settrans -ac /mnt /hurd/nfs hostname:/shared/directory +@end example + +What happens is the remote shared directory is visible on our /mnt directory. +We can then start copying,reading, and writing files like they were our own. +This is just the basics of the NFS protocol. If you are very interested in +NFS there is limitless amounts of documentation on the Internet. It is well +known to be insecure so be very careful with what your doing. + +@node Web Surfing +@comment node,next, prev,up +@section Web Surfing + +On the Hurd we can surf the web on the console. The program that we use is +called Lynx. Lynx is a text mode web browser. The benefits of using a text +mode web browser is speed and simplicity. In text mode you don't have to load +any graphics. You also don't get those annoying pop-ups and other annoyances +that are involved with the World Wide Web. To use lynx you type the command +@code{lynx}then a URL like this example. + +@example +bash-2.05$ lynx www.google.com <ENTER> +@end example + +This starts us out with google.com. To go to another URL you type the letter +'g' meaning Go. Lynx then prompts you for a address to go to. Accessing links +on a web page you would press the 'Right' button. To go back you would press +the 'Left' button. To get help with lynx pressing the 'h' button gives us a +big section of help topics. You can even download information by placing +the cursor over the item you want and pressing the 'p' button. Lynx then +prompts us to "Save to File" or "Print". Lynx is very addictive and once you +get used to it you might not want anything else. + @node Translators +@comment node, next, prev, up @chapter Translators The Hurd filesystem allows you to set translators on any file or @@ -1167,7 +1470,7 @@ Whenever a program tries to access the contents of a translated node, the filesystem server redirects the request to the appropriate translator (starting it if necessary). Then, the new translator -services the client's request. The GNU C library makes this behaviour +services the client's request. The GNU C library makes this behavior seamless from the client's perspective, so that standard Unix programs behave correctly under the Hurd. @@ -1223,6 +1526,7 @@ @node Invoking settrans +@comment node, next, prev, up @section Invoking @code{settrans} @pindex settrans @@ -1327,6 +1631,7 @@ @node Invoking showtrans +@comment node, next, prev, up @section Invoking @code{showtrans} The @code{showtrans} program allows you to show the passive translator @@ -1358,10 +1663,12 @@ @node Invoking mount +@comment node, next, prev, up @section Invoking @code{mount} @node Invoking fsysopts +@comment node, next, prev, up @section Invoking @code{fsysopts} The @code{fsysopts} program allows you to retrieve or set command line @@ -1400,4 +1707,2271 @@ If no options are supplied, @var{filesys}' current options are printed. +@node Reference Manual +@comment node, Next, Prev , Up +@chapter Reference Manual + +To start programming the Hurd you may want to start with Wolfgang Jahrling's + @uref{http://www.8ung.at/shell/hhg.html,Hurd Hackers Guide}. The pre-requisite +for learning to program the Hurd is knowing the C programming language. You +should also read about the gnumach microkernel because the Hurd servers +currently use it. It also helps if you have it installed and running with +the tools you need. + +@node Foundations +@comment node, Next, Prev , Up +@section Foundations + +Every Hurd program accepts the following optional arguments: + +@table @samp +@item --help +Display a brief usage message, then exit. This message is not a +substitute for reading program documentation; rather, it provides useful +reminders about specific command-line options that a program +understands. + +@item --version +Output program version information and exit. +@end table + +The rest of this chapter provides a programmer's introduction to the +Hurd. If you are not a programmer, then this chapter will not make much +sense to you@dots{} you should consider skipping to descriptions of +specific Hurd programs (@pxref{Audience}). + +The Hurd distribution includes many libraries in order to provide a +useful set of tools for writing Hurd utilities and servers. Several of +these libraries are useful not only for the Hurd, but also for writing +microkernel-based programs in general. These fundamental libraries are +not difficult to understand, and they are a good starting point, because +the rest of the Hurd relies upon them quite heavily. + +@menu +* Threads Library:: Every Hurd server and library is multithreaded. +* Ports Library:: Managing server port receive rights. +* Integer Hash Library:: Integer-keyed hash tables. +* Misc Library:: Things that soon will be in the GNU C library. +* Bug Address Library:: Where to report Hurd bugs. +@end menu + +@node Threads Library +@comment node, Next, Prev , Up +@section Threads Library +@scindex libthreads +@scindex cthreads.h + +All Hurd servers and libraries are aggressively multithreaded in order +to take full advantage of any multiprocessing capabilities provided by +the microkernel and the underlying hardware. The Hurd threads library, +@code{libthreads}, contains the default Hurd thread implementation, which +is declared in @code{<cthreads.h>}. + +Currently (April 1998), the Hurd uses cthreads, which have already been +documented thoroughly by CMU. Eventually, it will be migrated to use +POSIX pthreads, which are documented in a lot of places. +@c Thomas, 26-03-1998 + +@c FIXME: it would be nice if we referred specifically to some of +@c the places in which POSIX pthreads are documented. +@c tb: yes, but alas we are only allowed to refer to free +@c documentation, and IEEE Posix ain't that... ;-( + +Every single library in the Hurd distribution (including the GNU C +library) is completely thread-safe, and the Hurd servers themselves are +aggressively multithreaded. + + +@node Ports Library +@comment node, Next, Prev , Up +@section Ports Library +@scindex libports +@scindex ports.h + +Ports are communication channels that are held by the kernel. + +A port has separate send rights and receive rights, which may be +transferred from task to task via the kernel. Port rights are similar +to Unix file descriptors: they are per-task integers which are used to +identify ports when making kernel calls. Send rights are required in +order to send an RPC request down a port, and receive rights are +required to serve the RPC request. Receive rights may be aggregated +into a single @dfn{portset}, which serve as useful organizational units. + +In a single-threaded RPC client, managing and categorizing ports is not +a difficult process. However, in a complex multithreaded server, it is +useful to have a more abstract interface to managing portsets, as well +as maintaining server metadata. + +The Hurd ports library, @code{libports}, fills that need. The +@code{libports} functions are declared in @code{<hurd/ports.h>}. + +@menu +* Buckets and Classes:: Basic units of port organization. +* Port Rights:: Moving port rights to and from @code{libports}. +* Port Metadata:: Managing port-related information. +* Port References:: Guarding against leaks and lossage. +* RPC Management:: Locking and interrupting RPC operations. +@end menu + +@node Buckets and Classes +@comment node, Next, Prev , Up +@subsection Buckets and Classes + +The @code{libports} @dfn{bucket} is simply a port set, with some +metadata and a lock. All of the @code{libports} functions operate on +buckets. + +@deftypefun {struct port_bucket *} ports_create_bucket (void) +Create and return a new, empty bucket. +@end deftypefun + +A port @dfn{class} is a collection of individual ports, which can be +manipulated conveniently, and have enforced deallocation routines. +Buckets and classes are entirely orthogonal: there is no requirement +that all the ports in a class be in the same bucket, nor is there a +requirement that all the ports in a bucket be in the same class. + +@deftypefun {struct port_class} ports_create_class (@w{void (*@var{clean_routine}) (void *@var{port})}, @w{void (*@var{dropweak_routine}) (void *@var{port})}) +Create and return a new port class. If nonzero, @var{clean_routine} +will be called for each allocated port object in this class when it is +being destroyed. If nonzero, @var{dropweak_routine} will be called to +request weak references to be dropped. (If @var{dropweak_routine} is +null, then weak references and hard references will be identical for +ports of this class.) +@end deftypefun + +Once you have created at least one bucket and class, you may create new +ports, and store them in those buckets. There are a few different +functions for port creation, depending on your application's +requirements: + +@deftypefun error_t ports_create_port (@w{struct port_class *@var{class}}, @w{struct port_bucket *@var{bucket}}, @w{size_t @var{size}}, @w{void *@var{result}}) +Create and return in @var{result} a new port in @var{class} and +@var{bucket}; @var{size} bytes will be allocated to hold the port +structure and whatever private data the user desires. +@end deftypefun + +@deftypefun error_t ports_create_port_noinstall (@w{struct port_class *@var{class}}, @w{struct port_bucket *@var{bucket}}, @w{size_t @var{size}}, @w{void *@var{result}}) +Just like @code{ports_create_port}, except don't actually put the port +into the portset underlying @var{bucket}. This is intended to be used +for cases where the port right must be given out before the port is +fully initialized; with this call you are guaranteed that no RPC service +will occur on the port until you have finished initializing it and +installed it into the portset yourself. +@end deftypefun + +@deftypefun error_t ports_import_port (@w{struct port_class *@var{class}}, @w{struct port_bucket *@var{bucket}}, @w{mach_port_t @var{port}}, @w{size_t @var{size}}, @w{void *@var{result}}) +For an existing @emph{receive} right, create and return in @var{result} +a new port structure; @var{bucket}, @var{size}, and @var{class} args are +as for @code{ports_create_port}. +@end deftypefun + + +@node Port Rights +@comment node, Next, Prev , Up +@subsection Port Rights + +The following functions move port receive rights to and from the port +structure: + +@deftypefun void ports_reallocate_port (@w{void *@var{port}}) +Destroy the receive right currently associated with @var{port} and +allocate a new one. +@end deftypefun + +@deftypefun void ports_reallocate_from_external (@w{void *@var{port}}, @w{mach_port_t @var{receive}}) +Destroy the receive right currently associated with @var{port} and +designate @var{receive} as the new one. +@end deftypefun + +@deftypefun void ports_destroy_right (@w{void *@var{port}}) +Destroy the receive right currently associated with @var{port}. After +this call, @code{ports_reallocate_port} and +@code{ports_reallocate_from_external} may not be used. +@end deftypefun + +@deftypefun mach_port_t ports_claim_right (@w{void *@var{port}}) +Return the receive right currently associated with @var{port}. The +effects on @var{port} are the same as in @code{ports_destroy_right}, +except that the receive right itself is not affected. Note that in +multi-threaded servers, messages might already have been dequeued for +this port before it gets removed from the portset; such messages will +get @code{EOPNOTSUPP} errors. +@end deftypefun + +@deftypefun error_t ports_transfer_right (@w{void *@var{topt}}, @w{void *@var{frompt}}) +Transfer the receive right from @var{frompt} to @var{topt}. +@var{frompt} ends up with a destroyed right (as if +@code{ports_destroy_right} were called) and @var{topt}'s old right is +destroyed (as if @code{ports_reallocate_from_external} were called). +@end deftypefun + +@deftypefun mach_port_t ports_get_right (@w{void *@var{port}}) +Return the name of the receive right associated with @var{port}. The +user is responsible for creating an ordinary send right from this name. +@end deftypefun + + +@node Port Metadata +@comment node, Next, Prev , Up +@subsection Port Metadata + +It is important to point out that the @var{port} argument to each of +the @code{libports} functions is a @code{void *} and not a @code{struct +port_info *}. This is done so that you may add arbitrary +meta-information to your @code{libports}-managed ports. Simply define +your own structure whose first element is a @code{struct port_info}, and +then you can use pointers to these structures as the @var{port} argument +to any @code{libports} function. + +The following functions are useful for maintaining metadata that is +stored in your own custom ports structure: + +@deftypefun {void *} ports_lookup_port (@w{struct port_bucket *@var{bucket}}, @w{mach_port_t @var{port}}, @w{struct port_class *@var{class}}) +Look up @var{port} and return the associated port structure, allocating +a reference. If the call fails, return zero. If @var{bucket} is nonzero, +then it specifies a bucket to search; otherwise all buckets will be +searched. If @var{class} is nonzero, then the lookup will fail if +@var{port} is not in @var{class}. +@end deftypefun + +@deftypefun error_t ports_bucket_iterate (@w{struct port_bucket *@var{bucket}}, @w{error_t (*@var{fun}) (void *@var{port})}) +Call @var{fun} once for each port in @var{bucket}. No guarantee is made +about the order of iteration, which might vary from call to call. If +FUN returns an error, then no further calls to FUN are made for any +remaining ports, and the return value of FUN is returned from +ports_bucket_iterate. +@end deftypefun + +@node Port References +@comment node, Next, Prev , Up +@subsection Port References + +These functions maintain references to ports so that the port +information structures may be freed if and only if they are no longer +needed. It is your responsibility to tell @code{libports} when +references to ports change. + +@deftypefun void ports_port_ref (@w{void *@var{port}}) +Allocate a hard reference to @var{port}. +@end deftypefun + +@deftypefun void ports_port_deref (@w{void *@var{port}}) +Drop a hard reference to @var{port}. +@end deftypefun + +@deftypefun void ports_no_senders (@w{void *@var{port}}, @w{mach_port_mscount_t @var{mscount}}) +The user is responsible for listening for no senders notifications; when +one arrives, call this routine for the @var{port} the message was sent +to, providing the @var{mscount} from the notification. +@end deftypefun + +@deftypefun int ports_count_class (@w{struct port_class *@var{class}}) +Block creation of new ports in @var{class}. Return the number of ports +currently in @var{class}. +@end deftypefun + +@deftypefun int ports_count_bucket (@w{struct port_bucket *@var{bucket}}) +Block creation of new ports in @var{bucket}. Return the number of ports +currently in @var{bucket}. +@end deftypefun + +@deftypefun void ports_enable_class (@w{struct port_class *@var{class}}) +Permit suspended port creation (blocked by @code{ports_count_class}) to +continue. +@end deftypefun + +@deftypefun void ports_enable_bucket (@w{struct port_bucket *@var{bucket}}) +Permit suspended port creation (blocked by @code{ports_count_bucket}) to +continue. +@end deftypefun + +Weak references are not often used, as they are the same as hard +references for port classes where @var{dropweak_routine} is null. +@xref{Buckets and Classes}. + +@deftypefun void ports_port_ref_weak (@w{void *@var{port}}) +Allocate a weak reference to @var{port}. +@end deftypefun + +@deftypefun void ports_port_deref_weak (@w{void *@var{port}}) +Drop a weak reference to @var{port}. +@end deftypefun + + +@node RPC Management +@comment node, Next, Prev , Up +@subsection RPC Management + +The rest of the @code{libports} functions are dedicated to controlling +RPC operations. These functions help you do all the locking and thread +cancellations that are required in order to build robust servers. + +@deftypefn {Typedef} {typedef int (*} ports_demuxer_type ) (@w{mach_msg_header_t *@var{inp}}, @w{mach_msg_header_t *@var{outp}}) +Type of MiG demuxer routines. +@end deftypefn + +@c FIXME: Should I know what `MiG' means? +@c tb: Yeah, it's the Mach Interface Generator. + +@deftypefun error_t ports_begin_rpc (@w{void *@var{port}}, @w{mach_msg_id_t @var{msg_id}}, @w{struct rpc_info *@var{info}}) +Call this when an RPC is beginning on @var{port}. @var{info} should be +allocated by the caller and will be used to hold dynamic state. If this +RPC should be abandoned, return @code{EDIED}; otherwise we return zero. +@end deftypefun + +@deftypefun void ports_end_rpc (@w{void *@var{port}}, @w{struct rpc_info *@var{info}}) +Call this when an RPC is concluding. The arguments must match the ones +passed to the paired call to @code{ports_begin_rpc}. +@end deftypefun + +@deftypefun void ports_manage_port_operations_one_thread (@w{struct port_bucket *@var{bucket}}, @w{ports_demuxer_type @var{demuxer}}, @w{int @var{timeout}}) +Begin handling operations for the ports in @var{bucket}, calling +@var{demuxer} for each incoming message. Return if @var{timeout} is +nonzero and no messages have been received for @var{timeout} +milliseconds. Use only one thread (the calling thread). +@end deftypefun + +@deftypefun void ports_manage_port_operations_multithread (@w{struct port_bucket *@var{bucket}}, @w{ports_demuxer_type @var{demuxer}}, @w{int @var{thread_timeout}}, @w{int @var{global_timeout}}, @w{void (*@var{hook}) (void)}) +Begin handling operations for the ports in @var{bucket}, calling +@var{demuxer} for each incoming message. Return if @var{global_timeout} +is nonzero and no messages have been received for @var{global_timeout} +milliseconds. Create threads as necessary to handle incoming messages +so that no port is starved because of sluggishness on another port. If +@var{thread_timeout} is nonzero, then individual threads will die off +if they handle no incoming messages for @var{local_timeout} +milliseconds. If non-null, @var{hook} will be called in each new thread +immediately after it is created. +@end deftypefun + +@deftypefun error_t ports_inhibit_port_rpcs (@w{void *@var{port}}) +Interrupt any pending RPC on @var{port}. Wait for all pending RPCs to +finish, and then block any new RPCs starting on that port. +@end deftypefun + +@deftypefun error_t ports_inhibit_class_rpcs (@w{struct port_class *@var{class}}) +Similar to @code{ports_inhibit_port_rpcs}, but affects all ports in +@var{class}. +@end deftypefun + +@deftypefun error_t ports_inhibit_bucket_rpcs (@w{struct port_bucket *@var{bucket}}) +Similar to @code{ports_inhibit_port_rpcs}, but affects all ports in +@var{bucket}. +@end deftypefun + +@deftypefun error_t ports_inhibit_all_rpcs (void) +Similar to @code{ports_inhibit_port_rpcs}, but affects all ports +whatsoever. +@end deftypefun + +@deftypefun void ports_resume_port_rpcs (@w{void *@var{port}}) +Reverse the effect of a previous @code{ports_inhibit_port_rpcs} for this +@var{port}, allowing blocked RPCs to continue. +@end deftypefun + +@deftypefun void ports_resume_class_rpcs (@w{struct port_class *@var{class}}) +Reverse the effect of a previous @code{ports_inhibit_class_rpcs} for +@var{class}. +@end deftypefun + +@deftypefun void ports_resume_bucket_rpcs (@w{struct port_bucket *@var{bucket}}) +Reverse the effect of a previous @code{ports_inhibit_bucket_rpcs} for +@var{bucket}. +@end deftypefun + +@deftypefun void ports_resume_all_rpcs (void) +Reverse the effect of a previous @code{ports_inhibit_all_rpcs}. +@end deftypefun + +@deftypefun void ports_interrupt_rpcs (@w{void *@var{port}}) +Cancel (with @code{thread_cancel}) any RPCs in progress on @var{port}. +@end deftypefun + +@deftypefun int ports_self_interrupted (void) +If the current thread's RPC has been interrupted with +@code{ports_interrupt_rpcs}, return nonzero and clear the interrupted +flag. +@end deftypefun + +@deftypefun error_t ports_interrupt_rpc_on_notification (@w{void *@var{object}}, @w{struct rpc_info *@var{rpc}}, @w{mach_port_t @var{port}}, @w{mach_msg_id_t @var{what}}) +Arrange for @code{hurd_cancel} to be called on @var{rpc}'s thread if +@var{object} gets notified that any of the things in @var{what} have +happened to @var{port}. @var{rpc} should be an RPC on @var{object}. +@end deftypefun + +@deftypefun error_t ports_interrupt_self_on_notification (@w{void *@var{object}}, @w{mach_port_t @var{port}}, @w{mach_msg_id_t @var{what}}) +Arrange for @code{hurd_cancel} to be called on the current thread, which +should be an RPC on @var{object}, if @var{port} gets notified with the +condition @var{what}. +@end deftypefun + +@deftypefun error_t ports_interrupt_self_on_port_death (@w{void *@var{object}}, @w{mach_port_t @var{port}}) +Same as calling @code{ports_interrupt_self_on_notification} with +@var{what} set to @code{MACH_NOTIFY_DEAD_NAME}. +@end deftypefun + +@deftypefun void ports_interrupt_notified_rpcs (@w{void *@var{object}}, @w{mach_port_t @var{port}}, @w{mach_msg_id_t @var{what}}) +Interrupt any RPCs on @var{object} that have requested such. +@end deftypefun + +@deftypefun void ports_dead_name (@w{void *@var{object}}, @w{mach_port_t @var{port}}) +Same as calling @code{ports_interrupt_notified_rpcs} with @var{what} set +to @code{MACH_NOTIFY_DEAD_NAME}. +@end deftypefun + + +@node Integer Hash Library +@comment node, Next, Prev , Up +@section Integer Hash Library +@scindex libihash +@scindex ihash.h + +@code{libihash} provides integer-keyed hash tables, for arbitrary +element data types. Such hash tables are frequently used when +implementing sparse arrays or buffer caches. + +The following functions are declared in @code{<hurd/ihash.h>}: + +@deftypefun error_t ihash_create (@w{ihash_t *@var{ht}}) +Create an integer hash table and return it in @var{ht}. If a memory +allocation error occurs, @code{ENOMEM} is returned, otherwise zero. +@end deftypefun + +@deftypefun void ihash_free (@w{ihash_t @var{ht}}) +Free @var{ht} and all resources it consumes. +@end deftypefun + +@deftypefun void ihash_set_cleanup (@w{ihash_t @var{ht}}, @w{void (*@var{cleanup}) (void *@var{value}, void *@var{arg})}, @w{void *@var{arg}}) +Sets @var{ht}'s element cleanup function to @var{cleanup}, and its +second argument to @var{arg}. @var{cleanup} will be called on every +element @var{value} to be subsequently overwritten or deleted, with +@var{arg} as the second argument. +@end deftypefun + +@deftypefun error_t ihash_add (@w{ihash_t @var{ht}}, @w{int @var{id}}, @w{void *@var{item}}, @w{void ***@var{locp}}) +Add @var{item} to the hash table @var{ht} under the integer key +@var{id}. @var{locp} is the address of a pointer located in @var{item}; +If non-null, @var{locp} should point to a variable of type @code{void +**}, and will be filled with a pointer that may be used as an argument +to @code{ihash_locp_remove}. The variable pointed to by @var{locp} may +be overwritten sometime between this call and when the element is +deleted, so you cannot stash its value elsewhere and hope to use the +stashed value with @code{ihash_locp_remove}. If a memory allocation +error occurs, @code{ENOMEM} is returned, otherwise zero. +@end deftypefun + +@deftypefun {void *} ihash_find (@w{ihash_t @var{ht}}, @w{int @var{id}}) +Find and return the item in hash table @var{ht} with key @var{id}. +Returns null if the specified item doesn't exist. +@end deftypefun + +@deftypefun error_t ihash_iterate (@w{ihash_t @var{ht}}, @w{error_t (*@var{fun}) (void *@var{value})}) +Call function @var{fun} on every element of @var{ht}. @var{fun}'s only +arg, @var{value}, is a pointer to the value stored in the hash table. If +@var{fun} ever returns nonzero, then iteration stops and +@code{ihash_iterate} returns that value, otherwise it (eventually) +returns 0. +@end deftypefun + +@deftypefun int ihash_remove (@w{ihash_t @var{ht}}, @w{int @var{id}}) +Remove the entry with a key of @var{id} from @var{ht}. If there was no +such element, then return zero, otherwise nonzero. +@end deftypefun + +@deftypefun void ihash_locp_remove (@w{ihash_t @var{ht}}, @w{void **@var{ht_locp}}) +Remove the entry at @var{locp} from the hashtable @var{ht}. @var{locp} +is as returned from an earlier call to @code{ihash_add}. This call +should be faster than @code{ihash_remove}. @var{ht} can be null, in +which case the call still succeeds, but no cleanup is done. +@end deftypefun + + +@node Misc Library +@comment node, Next, Prev , Up +@section Misc Library +@scindex libshouldbeinlibc + +The GNU C library is constantly developing to meet the needs of the +Hurd. However, because the C library needs to be very stable, it is +irresponsible to add new functions to it without carefully specifying +their interface, and testing them thoroughly. + +The Hurd distribution includes a library called +@code{libshouldbeinlibc}, which serves as a proving ground for additions +to the GNU C library. This library is in flux, as some functions are +added to it by the Hurd developers and others are moved to the official +C library. + +These functions aren't currently documented (other than in their header +files), but complete documentation will be added to +@iftex +@emph{The GNU C Library Reference Manual} +@end iftex +@ifinfo +@ref{Top, The GNU C Library Reference Manual,, libc}, +@end ifinfo +when these functions become part of the GNU C library. + + +@node Bug Address Library +@comment node, Next, Prev , Up +@section Bug Address Library +@scindex libhurdbugaddr + +@code{libhurdbugaddr} exists only to define a single variable: + +@deftypevar {char *} argp_program_bug_address +@code{argp_program_bug_address} is the default Hurd bug-reporting e-mail +address, @email{bug-hurd@@gnu.org}. This address is displayed to the +user when any of the standard Hurd servers and utilities are invoked +using the @samp{--help} option. +@end deftypevar + +@node Input and Output +@comment node, Next, Prev , Up +@section Input and Output + +There are no specific programs or servers associated with the I/O +subsystem, since it is used to interact with almost all servers in the +GNU Hurd. It provides facilities for reading and writing I/O channels, +which are the underlying implementation of file and socket descriptors +in the GNU C library. + +@menu +* Iohelp Library:: I/O authentication and lock management. +* Pager Library:: Implementing multithreaded external pagers. +* I/O Interface:: RPC-based input/output channels. +@end menu + +@node Iohelp Library +@comment node, Next, Prev , Up +@section Iohelp Library +@scindex libiohelp +@scindex iohelp.h + +The @code{<hurd/iohelp.h>} file declares several functions which are +useful for low-level I/O implementations. Most Hurd servers do not call +these functions directly, but they are used by several of the Hurd +filesystem and networking helper libraries. @code{libiohelp} requires +@code{libthreads}. + +@menu +* I/O Users:: User authentication management. +* Conch Management:: Deprecated shared I/O implementation. +@end menu + +@node I/O Users +@comment node, Next, Prev , Up +@subsection I/O Users + +Most I/O servers need to implement some kind of user authentication +checking. In order to facilitate that process, @code{libiohelp} has +some functions which encapsulate a set of idvecs (FIXME: xref to C +library) in a single @code{struct iouser}. + +@deftypefun {struct iouser *} iohelp_create_iouser (@w{struct idvec *@var{uids}}, @w{struct idvec *@var{gids}}) +Create a new @var{iouser} for the specified @var{uids} and @var{gids}. +@end deftypefun + +@deftypefun {struct iouser *} iohelp_dup_iouser (@w{struct iouser *@var{iouser}}) +Return a copy of @var{iouser}. +@end deftypefun + +@deftypefun void iohelp_free_iouser (@w{struct iouser *@var{iouser}}) +Release a reference to @var{iouser}. +@end deftypefun + +I/O reauthentication is a rather complex protocol involving the +authserver as a trusted third party (@pxref{Auth Protocol}). In order +to reduce the risk of flawed implementations, I/O reauthentication is +encapsulated in the @code{iohelp_reauth} function: + +@deftypefun {struct iouser *} iohelp_reauth (@w{auth_t @var{authserver}}, @w{mach_port_t @var{rend_port}}, @w{mach_port_t @var{newright}}, @w{int @var{permit_failure}}) +Conduct a reauthentication transaction, and return a new @var{iouser}. +@var{authserver} is the I/O server's auth port. The rendezvous port +provided by the user is @var{rend_port}. + +If the transaction cannot be completed, return zero, unless +@var{permit_failure} is nonzero. If @var{permit_failure} is nonzero, +then should the transaction fail, return an @var{iouser} that has no +ids. The new port to be sent to the user is @var{newright}. +@end deftypefun + + +@node Conch Management +@comment node, Next, Prev , Up +@subsection Conch Management + +@cindex conch +@findex iohelp_initialize_conch +@findex iohelp_handle_io_get_conch +@findex iohelp_get_conch +@findex iohelp_handle_io_release_conch +@findex iohelp_verify_user_conch +@findex iohelp_fetch_shared_data +@findex iohelp_put_shared_data +The @dfn{conch} is at the heart of the shared memory I/O system. +Several Hurd libraries implement shared I/O, and so @code{libiohelp} +contains functions to facilitate conch management. + +Everything about shared I/O is undocumented because it is not needed for +adequate performance, and the RPC interface is simpler (@pxref{I/O +Interface}). It is not useful for new libraries or servers to implement +shared I/O. + + +@node Pager Library +@comment node, Next, Prev , Up +@section Pager Library +@scindex libpager +@scindex pager.h + +@cindex XP (external pager) +@cindex external pager (XP) +The @dfn{external pager} (@dfn{XP}) microkernel interface allows +applications to provide the backing store for a memory object, by +converting hardware page faults into RPC requests. External pagers are +required for memory-mapped I/O (@pxref{Mapped Data}) and stored +filesystems (@pxref{Stored Filesystems}). + +The external pager interface is quite complex, so the Hurd pager library +contains functions which aid in creating multithreaded external pagers. +@code{libpager} is declared in @code{<hurd/pager.h>}, and requires only +the threads and ports libraries. + +@menu +* Pager Management:: High-level interface to external pagers. +* Pager Callbacks:: Functions that the user must define. +@end menu + + +@node Pager Management +@comment node, Next, Prev , Up +@subsection Pager Management + +The pager library defines the @code{struct pager} data type in order to +represent a multi-threaded pager. The general procedure for creating a +pager is to define the functions listed in @ref{Pager Callbacks}, +allocate a @code{libports} bucket for the ports which will access the +pager, and create at least one new @code{struct pager} with +@code{pager_create}. + +@deftypefun {struct pager *} pager_create (@w{struct user_pager_info *@var{u_pager}}, @w{struct port_bucket *@var{bucket}}, @w{boolean_t @var{may_cache}}, @w{memory_object_copy_strategy_t @var{copy_strategy}}) +Create a new pager. The pager will have a port created for it (using +@code{libports}, in @var{bucket}) and will be immediately ready to +receive requests. @var{u_pager} will be provided to later calls to +@code{pager_find_address}. The pager will have one user reference +created. @var{may_cache} and @var{copy_strategy} are the original +values of those attributes as for @code{memory_object_ready}. Users may +create references to pagers by use of the relevant ports library +functions. On errors, return null and set @code{errno}. +@end deftypefun + +Once you are ready to turn over control to the pager library, you should +call @code{ports_manage_port_operations_multithread} on the +@var{bucket}, using @code{pager_demuxer} as the ports @var{demuxer}. +This will handle all external pager RPCs, invoking your pager callbacks +when necessary. + +@deftypefun int pager_demuxer (@w{mach_msg_header_t *@var{inp}}, @w{mach_msg_header_t *@var{outp}}) +Demultiplex incoming @code{libports} messages on pager ports. +@end deftypefun + +The following functions are the body of the pager library, and provide a +clean interface to pager functionality: + +@deftypefun void pager_sync (@w{struct pager *@var{pager}}, @w{int @var{wait}}) +@deftypefunx void pager_sync_some (@w{struct pager *@var{pager}}, @w{vm_address_t @var{start}}, @w{vm_size_t @var{len}}, @w{int @var{wait}}) +Write data from pager @var{pager} to its backing store. Wait for all +the writes to complete if and only if @var{wait} is set. + +@code{pager_sync} writes all data; @code{pager_sync_some} only writes +data starting at @var{start}, for @var{len} bytes. +@end deftypefun + +@deftypefun void pager_flush (@w{struct pager *@var{pager}}, @w{int @var{wait}}) +@deftypefunx void pager_flush_some (@w{struct pager *@var{pager}}, @w{vm_address_t @var{start}}, @w{vm_size_t @var{len}}, @w{int @var{wait}}) +Flush data from the kernel for pager @var{pager} and force any pending +delayed copies. Wait for all pages to be flushed if and only if +@var{wait} is set. + +@code{pager_flush} flushes all data; @code{pager_flush_some} only +flushes data starting at @var{start}, for @var{len} bytes. +@end deftypefun + +@deftypefun void pager_return (@w{struct pager *@var{pager}}, @w{int @var{wait}}) +@deftypefunx void pager_return_some (@w{struct pager *@var{pager}}, @w{vm_address_t @var{start}}, @w{vm_size_t @var{len}}, @w{int @var{wait}}) +Flush data from the kernel for pager @var{pager} and force any pending +delayed copies. Wait for all pages to be flushed if and only if +@var{wait} is set. Have the kernel write back modifications. + +@code{pager_return} flushes and restores all data; +@code{pager_return_some} only flushes and restores data starting at +@var{start}, for @var{len} bytes. +@end deftypefun + +@deftypefun void pager_offer_page (@w{struct pager *@var{pager}}, @w{int @var{precious}}, @w{int @var{writelock}}, @w{vm_offset_t @var{page}}, @w{vm_address_t @var{buf}}) +Offer a page of data to the kernel. If @var{precious} is set, then this +page will be paged out at some future point, otherwise it might be +dropped by the kernel. If the page is currently in core, the kernel +might ignore this call. +@end deftypefun + +attributes@deftypefun void pager_change_attributes (@w{struct pager *@var{pager}}, @w{boolean_t @var{may_cache}}, @w{memory_object_copy_strategy_t @var{copy_strategy}}, @w{int @var{wait}}) +Change the attributes of the memory object underlying pager @var{pager}. +The @var{may_cache} and @var{copy_strategy} arguments are as for +@code{memory_object_change_}. Wait for the kernel to report +completion if and only if @var{wait} is set. +@end deftypefun + +@deftypefun void pager_shutdown (@w{struct pager *@var{pager}}) +Force termination of a pager. After this returns, no more paging +requests on the pager will be honoured, and the pager will be +deallocated. The actual deallocation might occur asynchronously if +there are currently outstanding paging requests that will complete +first. +@end deftypefun + +@deftypefun error_t pager_get_error (@w{struct pager *@var{p}}, @w{vm_address_t @var{addr}}) +Return the error code of the last page error for pager @var{p} at +address @var{addr}.@footnote{Note that this function will be deleted +when the Mach pager interface is fixed to provide this information.} +@end deftypefun + +@deftypefun error_t pager_memcpy (@w{struct pager *@var{pager}}, @w{memory_object_t @var{memobj}}, @w{vm_offset_t @var{offset}}, @w{void *@var{other}}, @w{size_t *@var{size}}, @w{vm_prot_t @var{prot}}) +Try to copy @code{*@var{size}} bytes between the region @var{other} +points to and the region at @var{offset} in the pager indicated by +@var{pager} and @var{memobj}. If @var{prot} is @code{VM_PROT_READ}, +copying is from the pager to @var{other}; if @var{prot} contains +@code{VM_PROT_WRITE}, copying is from @var{other} into the pager. +@code{*@var{size}} is always filled in with the actual number of bytes +successfully copied. Returns an error code if the pager-backed memory +faults; if there is no fault, returns zero and @code{*@var{size}} will +be unchanged. +@end deftypefun + +These functions allow you to recover the internal @code{struct pager} +state, in case the @code{libpager} interface doesn't provide an +operation you need: + +@deftypefun {struct user_pager_info *} pager_get_upi (@w{struct pager *@var{p}}) +Return the @code{struct user_pager_info} associated with a pager. +@end deftypefun + +@deftypefun mach_port_t pager_get_port (@w{struct pager *@var{pager}}) +Return the port (receive right) for requests to the pager. It is +absolutely necessary that a new send right be created from this receive +right. +@end deftypefun + + +@node Pager Callbacks +@comment node, Next, Prev , Up +@subsection Pager Callbacks + +Like several other Hurd libraries, @code{libpager} depends on you to +implement application-specific callback functions. You @emph{must} +define the following functions: + +@deftypefun error_t pager_read_page (@w{struct user_pager_info *@var{pager}}, @w{vm_offset_t @var{page}}, @w{vm_address_t *@var{buf}}, @w{int *@var{write_lock}}) +For pager @var{pager}, read one page from offset @var{page}. Set +@code{*@var{buf}} to be the address of the page, and set +@code{*@var{write_lock}} if the page must be provided read-only. The +only permissible error returns are @code{EIO}, @code{EDQUOT}, and +@code{ENOSPC}. +@end deftypefun + +@deftypefun error_t pager_write_page (@w{struct user_pager_info *@var{pager}}, @w{vm_offset_t @var{page}}, @w{vm_address_t @var{buf}}) +For pager @var{pager}, synchronously write one page from @var{buf} to +offset @var{page}. In addition, @code{vm_deallocate} (or equivalent) +@var{buf}. The only permissible error returns are @code{EIO}, +@code{EDQUOT}, and @code{ENOSPC}. +@end deftypefun + +@deftypefun error_t pager_unlock_page (@w{struct user_pager_info *@var{pager}}, @w{vm_offset_t @var{address}}) +A page should be made writable. +@end deftypefun + +@deftypefun error_t pager_report_extent (@w{struct user_pager_info *@var{pager}}, @w{vm_address_t *@var{offset}}, @w{vm_size_t *@var{size}}) +This function should report in @code{*@var{offset}} and +@code{*@var{size}} the minimum valid address the pager will accept and +the size of the object. +@end deftypefun + +@deftypefun void pager_clear_user_data (@w{struct user_pager_info *@var{pager}}) +This is called when a pager is being deallocated after all extant send +rights have been destroyed. +@end deftypefun + +@deftypefun void pager_dropweak (@w{struct user_pager_info *@var{p}}) +This will be called when the ports library wants to drop weak +references. The pager library creates no weak references itself, so if +the user doesn't either, then it is all right for this function to do +nothing. +@end deftypefun + +@node I/O Interface +@comment node, Next, Prev , Up +@section I/O Interface +@scindex io.defs + +The I/O interface facilities are described in @code{<hurd/io.defs>}. +This section discusses only RPC-based I/O operations.@footnote{The +latter portion of @code{<hurd/io.defs>} and all of +@code{<hurd/shared.h>} describe how to implement shared-memory I/O +operations. However, shared I/O has been deprecated. @xref{Conch +Management}, for more details.} + +@menu +* I/O Object Ports:: How ports to I/O objects work. +* Simple Operations:: Read, write, and seek. +* Open Modes:: State bits that affect pieces of operation. +* Asynchronous I/O:: How to be notified when I/O is possible. +* Information Queries:: How to implement @code{io_stat} and + @code{io_server_version}. +* Mapped Data:: Getting memory objects referring to the + data of an I/O object. +@end menu + +@node I/O Object Ports +@comment node, Next, Prev , Up +@subsection I/O Object Ports + +The I/O server must associate each I/O port with a particular set of +uids and gids, identifying the user who is responsible for operations on +the port. Every port to an I/O server should also support either the +file protocol (@pxref{File Interface}) or the socket protocol +(@pxref{Socket Interface}); naked I/O ports are not allowed. + +In addition, the server associates with each port a default file +pointer, a set of open mode bits, a pid (called the ``owner''), and some +underlying object which can absorb data (for write) or provide data (for +read). + +The uid and gid sets associated with a port may not be visibly shared +with other ports, nor may they ever change. The server must fix the +identification of a set of uids and gids with a particular port at the +moment of the port's creation. The other characteristics of an I/O port +may be shared with other users. The I/O server interface does not +generally specify the way in which servers may share these other +characteristics (with the exception of the deprecated +@code{O_ASYNC} interface); however, the file and socket interfaces make +further requirements about what sharing is required and what sharing is prohibited. + +In general, users get send rights to I/O ports by some mechanism that is +external to the I/O protocol. (For example, fileservers give out I/O +ports in response to the @code{dir_lookup} and @code{fsys_getroot} +calls. Socket servers give out ports in response to the +@code{socket_create} and @code{socket_accept} calls.) However, the I/O +protocol provides methods of obtaining new ports that refer to the same +underlying object as another port. In response to all of these calls, +all underlying state (including, but not limited to, the default file +pointer, open mode bits, and underlying object) must be shared between +the old and new ports. In the following descriptions of these calls, +the term ``identical'' means this kind of sharing. All these calls must +return send rights to a newly-constructed Mach port. + +@c FIXME: should be say `Mach' above, or should we say +@c `microkernel'? +@c tb: We say Mach. Other kernels might have different rules, and we +@c should document what we have now. + +@findex io_duplicate +The @code{io_duplicate} call simply returns another port which is +identical to an existing port and has the same uid and gid set. + +@findex io_restrict_auth +The @code{io_restrict_auth} call returns another port, identical to the +provided port, but which has a smaller associated uid and gid set. The +uid and gid sets of the new port are the intersection of the set on the +existing port and the lists of uids and gids provided in the call. + +@findex io_reauthenticate +Users use the @code{io_reauthenticate} call when they wish to have an +entirely new set of uids or gids associated with a port. In response to +the @code{io_reauthenticate} call, the server must create a new port, +and then make the call @code{auth_server_authenticate} to the auth +server. The rendezvous port for the @code{auth_server_authenticate} +call is the I/O port to which was made the @code{io_reauthenticate} +call. The server provides the @var{rend_int} parameter to the auth +server as a copy from the corresponding parameter in the +@code{io_reauthenticate} call. The I/O server also gives the auth +server a new port; this must be a newly created port identical to the +old port. The authserver will return the set of uids and gids +associated with the user, and guarantees that the new port will go +directly to the user that possessed the associated authentication port. +The server then identifies the new port given out with the specified +ID's. + +@node Simple Operations +@comment node, Next, Prev , Up +@subsection Simple Operations + +@findex io_write +Users write to I/O ports by calling the @code{io_write} RPC. They +specify an @var{offset} parameter; if the object supports writing at +arbitrary offsets, the server should honour this parameter. If @math{-1} +is passed as the offset, then the server should use the default file +pointer. The server should return the amount of data which was +successfully written. If the operation was interrupted after some but +not all of the data was written, then it is considered to have succeeded +and the server should return the amount written. If the port is not an +I/O port at all, the server should reply with the error +@code{EOPNOTSUPP}. If the port is an I/O port, but does not happen to +support writing, then the correct error is @code{EBADF}. + +@findex io_read +Users read from I/O ports by calling the @code{io_read} RPC. They +specify the amount of data they wish to read, and the offset. The offset +has the same meaning as for @code{io_write} above. The server should +return the data that was read. If the call is interrupted after some +data has been read (and the operation is not idempotent) then the server +should return the amount read, even if it was less than the amount requested. +The server should return as much data as possible, but never more than +requested by the user. If there is no data, but there might be later, +the call should block until data becomes available. The server indicates +end-of-file by returning zero bytes. If the call is +interrupted after some data has been read, but the call is idempotent, +then the server may return @code{EINTR} rather than actually filling the +buffer (taking care that any modifications of the default file pointer +have been reversed). Preferably, however, servers should return data. + +There are two categories of objects: seekable and non-seekable. +Seekable objects must accept arbitrary offset parameters in the +@code{io_read} and @code{io_write} calls, and must implement the +@code{io_seek} call. Non-seekable objects must ignore the offset +parameters to @code{io_read} and @code{io_write}, and should return +@code{ESPIPE} to the @code{io_seek} call. + +@c FIXME: should that last `should' be replaced with `must'? +@c tb: maybe, but perhaps not. There might be a reason to implement a +@c semi-seekable object which permits some but not all of these +@c operations. In the case of the Hurd interfaces (as opposed to +@c libraries) I like to be a little looser about this. The rule is "do +@c what the interface says unless you really understand it and have a +@c good reason to do something different". + +@findex io_seek +On seekable objects, @code{io_seek} changes the default file pointer for +reads and writes. (@xref{File Positioning, , , libc, The GNU C Library +Reference Manual}, +for the interpretation of the @var{whence} and @var{offset} arguments.) +It returns the new offset as modified by @code{io_seek}. + +@findex io_readable +The @code{io_readable} interface returns the amount of data which can be +immediately read. For the special technical meaning of ``immediately'', +see @ref{Asynchronous I/O}. + +@node Open Modes +@comment node, Next, Prev , Up +@subsection Open Modes + +@findex io_set_all_openmodes +@findex io_get_openmodes +@findex io_set_some_openmodes +@findex io_clear_some_openmodes +The server associates each port with a set of bits that affect its +operation. The @code{io_set_all_openmodes} call modifies these bits and +the @code{io_get_openmodes} call returns them. In addition, the +@code{io_set_some_openmodes} and @code{io_clear_some_openmodes} do an +atomic read/modify/write of the openmodes. + +The @code{O_APPEND} bit, when set, changes the behaviour of +@code{io_write} when it uses the default file pointer on seekable +objects. When @code{io_write} is done on a port with the +@code{O_APPEND} bit set, is must set the file pointer to the current +file size before doing the write (which would then increment the file +pointer as usual). The @dfn{current file size} is the smallest offset +which returns end-of-file when provided to @code{io_read}. The server +must atomically bind this update to the actual data write with respect +to other users of @code{io_read}, @code{io_write}, and @code{io_seek}. + +The @code{O_FSYNC} bit, when set, guarantees that @code{io_write} will +not return until data is fully written to the underlying medium. + +The @code{O_NONBLOCK} bit, when set, prevents read and write from +blocking. They should copy such data as is immediately available. If +no data is immediately available they should return @code{EWOULDBLOCK}. + +The definition of ``immediately'' is more or less server-dependent. +Some servers, notably stored filesystem servers (@pxref{Stored +Filesystems}), regard all data as immediately available. The one +criterion is that something which must happen @dfn{immediately} may not +wait for any user-synchronizable event. + +The @code{O_ASYNC} bit is deprecated; its use is documented in the +following section. This bit must be shared between all users of the +same underlying object. + + +@node Asynchronous I/O +@comment node, Next, Prev , Up +@subsection Asynchronous I/O + +@findex io_async +Users may wish to be notified when I/O can be done without blocking; +they use the @code{io_async} call to indicate this to the server. In +the @code{io_async} call the user provides a port on which will the +server should send @code{sig_post} messages as I/O becomes possible. +The server must return a port which will be the reference port in the +@code{sig_post} messages. Each @code{io_async} call should generate a +new reference port. (FIXME: xref the C library manual for information +on how to send sig_post messages.) + +The server then sends one @code{SIGIO} signal to each registered async +user everytime I/O becomes possible. I/O is possible if at least one +byte can be read or written immediately. The definition of +``immediately'' must be the same as for the implementation of the +@code{O_NONBLOCK} flag (@pxref{Open Modes}). In addition, every time a +user calls @code{io_read} or @code{io_write} on a non-seekable object, or at the +default file pointer on a seekable object, another signal should be sent +to each user if I/O is still possible. + +Some objects may also define ``urgent'' conditions. Such servers should +send the @code{SIGURG} signal to each registered async user anytime an +urgent condition appears. After any RPC that has the possibility of +clearing the urgent condition, the server should again send the signal +to all registered users if the urgent condition is still present. + +@findex io_select +A more fine-grained mechanism for doing async I/O is the +@code{io_select} call. The user specifies the kind of access desired, +and a send-once right. If I/O of the kind the user desires is +immediately possible, then the server should return so indicating, and +destroy the send-once right. If I/O is not immediately possible, the +server should save the send-once right, and send a @code{select_done} +message as soon as I/O becomes immediately possible. Again, the +definition of ``immediately'' must be the same for @code{io_select}, +@code{io_async}, and @code{O_NONBLOCK} (@pxref{Open Modes}). + +@findex io_mod_owner +@findex io_get_owner +@findex io_get_icky_async_id +For compatibility with 4.2 and 4.3 BSD, the I/O interface provides a +deprecated feature (known as @dfn{icky async I/O}). The calls +@code{io_mod_owner} and @code{io_get_owner} set the ``owner'' of the +object, providing either a pid or a pgrp (if the value is negative). +This implies that only one process at a time can do icky I/O on a given +object. Whenever the I/O server is sending @code{sig_post} messages to +all the @code{io_async} users, if the @code{O_ASYNC} bit is set, the +server should also send a signal to the owning pid/pgrp. The ID port +for this call should be different from all the @code{io_async} ID ports +given to users. Users may find out what ID port the server uses for +this by calling @code{io_get_icky_async_id}. + +@node Information Queries +@comment node, Next, Prev , Up +@subsection Information Queries + +@findex io_stat +Users may call @code{io_stat} to find out information about the I/O +object. Most of the fields of a @code{struct stat} are meaningful only +for files. All objects, however, must support the fields +@var{st_fstype}, @var{st_fsid}, @var{st_ino}, @var{st_atime}, +@var{st_atime_usec}, @var{st_mtime_user}, @var{st_ctime}, +@var{st_ctime_usec}, and @var{st_blksize}. + +@var{st_fstype}, @var{st_fsid}, and @var{st_ino} must be unique for +the underlying object across the entire system. + +@var{st_atime} and @var{st_atime_usec} hold the seconds and +microseconds, respectively, of the system clock at the last time the +object was read with @code{io_read}. + +@var{st_mtime} and @var{st_mtime_usec} hold the seconds and microseconds, +respectively, of the system clock at the last time the object was +written with @code{io_write}. + +Other appropriate operations may update the @var{atime} and the +@var{mtime} as well; both the file and socket interfaces specify such +operations. + +@var{st_ctime} and @var{st_ctime_usec} hold the seconds and +microseconds, respectively, of the system clock at the last time +permanent meta-data associated with the object was changed. The exact +operations which cause such an update are server-dependent, but must +include the creation of the object. + +The server is permitted to delay the actual update of these times until +stat is called; before the server stores the times on permanent media +(if it ever does so) it should update them if necessary. + +@var{st_blksize} gives the optimal I/O size in bytes for @code{io_read} +and @code{io_write}; users should endeavor to read and write amounts +which are multiples of the optimal size, and to use offsets which are +multiples of the optimal size. + +In addition, objects which are seekable should set @var{st_size} to the +current file size as in the description of the @code{O_APPEND} flag +(@pxref{Open Modes}). + +The @var{st_uid} and @var{st_gid} fields are unrelated to the ``owner'' +as described above for icky async I/O. + +@findex io_server_version +Users may find out the version of the server they are talking to by +calling @code{io_server_version}; this should return strings and +integers describing the version number of the server, as well as its +name. + +@node Mapped Data +@comment node, Next, Prev , Up +@subsection Mapped Data + +@findex io_map +Servers may optionally implement the @code{io_map} call. The ports +returned by @code{io_map} must implement the external pager kernel +interface (@pxref{Pager Library}) and be suitable as arguments to +@code{vm_map}. + +Seekable objects must allow access from zero up to (but not including) +the current file size as described for @code{O_APPEND} (@pxref{Open +Modes}). Whether they provide access beyond such a point is +server-dependent; in addition, the meaning of accessing a non-seekable +object is server-dependent. + +@node Diskfs Library +@comment node, Next, Prev , Up +@section Diskfs Library +@scindex libdiskfs +@scindex diskfs.h + +The diskfs library is declared in @code{<hurd/diskfs.h>}, and does a lot +of the work of implementing stored filesystems. @code{libdiskfs} +requires the threads, ports, iohelp, fshelp, and store libraries. You +should understand all these libraries before you attempt to use diskfs, +and you should also be familiar with the pager library (@pxref{Pager +Library}). + +@scindex libstorefs +For historical reasons, the library for implementing stored filesystems +is called @code{libdiskfs} instead of @code{libstorefs}. Keep in mind, +however, that diskfs is useful for filesystems which are implemented on +any block-addressed storage device, since it uses the store library to +do I/O. + +Note that stored filesystems can be tricky to implement, since the +diskfs callback interfaces are not trivial. It really is best if you +examine the source code of a similar existing filesystem server, and +follow its example rather than trying to write your own from scratch. + +@menu +* Diskfs Startup:: Initializing stored filesystems. +* Diskfs Arguments:: Parsing command-line arguments. +* Diskfs Globals:: Global behaviour modification. +* Diskfs Node Management:: Allocation, reference counting, I/O, + caching, and other disk node routines. +* Diskfs Callbacks:: Mandatory user-defined diskfs functions. +* Diskfs Options:: Optional user-defined diskfs functions. +* Diskfs Internals:: Reimplementing small pieces of diskfs. +@end menu + + +@node Diskfs Startup +@comment node, Next, Prev , Up +@subsection Diskfs Startup + +This subsection gives an outline of the general steps involved in +implementing a filesystem server, to help refresh your memory and to +offer explanations rather than to serve as a tutorial. + +The first thing a filesystem server should do is parse its command-line +arguments (@pxref{Diskfs Arguments}). Then, the standard output and +error streams should be redirected to the console, so that error +messages are not lost if this is the bootstrap filesystem: + +@deftypefun void diskfs_console_stdio (void) +Redirect error messages to the console, so that they can be seen by +users. +@end deftypefun + +The following is a list of the relevant functions which would be called +during the rest of the server initialization. Again, you should refer +to the implementation of an already-working filesystem if you have any +questions about how these functions should be used: + +@deftypefun error_t diskfs_init_diskfs (void) +Call this function after arguments have been parsed to initialize the +library. You must call this before calling any other diskfs functions, +and after parsing diskfs options. +@end deftypefun + +@deftypefun void diskfs_spawn_first_thread (void) +Call this after all format-specific initialization is done (except for +setting @code{diskfs_root_node}); at this point the pagers should be +ready to go. +@end deftypefun + +@deftypefun mach_port_t diskfs_startup_diskfs (@w{mach_port_t @var{bootstrap}}, @w{int @var{flags}}) +Call this once the filesystem is fully initialized, to advertise the new +filesystem control port to our parent filesystem. If @var{bootstrap} is set, +diskfs will call @code{fsys_startup} on that port as appropriate and return +the @var{realnode} from that call; otherwise we call +@code{diskfs_start_bootstrap} and return @code{MACH_PORT_NULL}. +@var{flags} specifies how to open @var{realnode} (from the @code{O_*} set). +@end deftypefun + +You should not need to call the following function directly, since +@code{diskfs_startup_diskfs} will do it for you, when appropriate: + +@deftypefun void diskfs_start_bootstrap (void) +Start the Hurd bootstrap sequence as if we were the bootstrap filesystem +(that is, @code{diskfs_boot_flags} is nonzero). All filesystem +initialization must be complete before you call this function. +@end deftypefun + + +@node Diskfs Arguments +@comment node, Next, Prev , Up +@subsection Diskfs Arguments + +The following functions implement standard diskfs command-line and +runtime argument parsing, using argp (@pxref{Argp, , , libc, The GNU C +Library Reference Manual}): + +@deftypefun error_t diskfs_set_options (@w{char *@var{argz}}, @w{size_t @var{argz_len}}) +Parse and execute the runtime options specified by @var{argz} and +@var{argz_len}. @code{EINVAL} is returned if some option is +unrecognized. The default definition of this routine will parse them +using @code{diskfs_runtime_argp}. +@end deftypefun + +@deftypefun error_t diskfs_append_args (@w{char **@var{argz}}, @w{unsigned *@var{argz_len}}) +Append to the malloced string @code{*@var{argz}} of length +@code{*@var{argz_len}} a NUL-separated list of the arguments to this +translator. The default definition of this routine simply calls +@code{diskfs_append_std_options}. +@end deftypefun + +@deftypefun error_t diskfs_append_std_options (@w{char **@var{argz}}, @w{unsigned *@var{argz_len}}) +@emph{Appends} NUL-separated options describing the standard diskfs +option state to @var{argz} and increments @var{argz_len} appropriately. +Note that unlike @code{diskfs_get_options}, @var{argz} and +@var{argz_len} must already have sane values. +@end deftypefun + +@deftypevar {struct argp *} diskfs_runtime_argp +If this is defined or set to an argp structure, it will be used by the +default @code{diskfs_set_options} to handle runtime option parsing. The +default definition is initialized to a pointer to +@code{diskfs_std_runtime_argp}. +@end deftypevar + +@deftypevar {const struct argp} diskfs_std_runtime_argp +An argp for the standard diskfs runtime options. The default definition +of @code{diskfs_runtime_argp} points to this, although the user can +redefine that to chain this onto his own argp. +@end deftypevar + +@deftypevar {const struct argp} diskfs_startup_argp +An argp structure for the standard diskfs command line arguments. The +user may call @code{argp_parse} on this to parse the command line, chain +it onto the end of his own argp structure, or ignore it completely. +@end deftypevar + +@deftypevar {const struct argp} diskfs_store_startup_argp +An argp structure for the standard diskfs command line arguments plus a +store specification. The address of a location in which to return the +resulting @code{struct store_parsed} structure should be passed as the +input argument to @code{argp_parse}; FIXME xref the declaration for +STORE_ARGP. +@end deftypevar + + +@node Diskfs Globals +@comment node, Next, Prev , Up +@subsection Diskfs Globals + +The following functions and variables control the overall behaviour of +the library. Your callback functions may need to refer to these, but +you should not need to modify or redefine them. + +@deftypevar mach_port_t diskfs_default_pager +@deftypevarx mach_port_t diskfs_exec_ctl +@deftypevarx mach_port_t diskfs_exec +@deftypevarx auth_t diskfs_auth_server_port +These are the respective send rights to the default pager, execserver +control port, execserver itself, and authserver. +@end deftypevar + +@deftypevar mach_port_t diskfs_fsys_identity +The @code{io_identity} identity port for the filesystem. +@end deftypevar + +@deftypevar {char **} diskfs_argv +The command line with which diskfs was started, set by the default argument parser. +If you don't use it, set this yourself. This is only used for bootstrap +file systems, to give the procserver. +@end deftypevar + +@deftypevar {char *} diskfs_boot_flags +When this is a bootstrap filesystem, the command line options passed from +the kernel. If not a bootstrap filesystem, it is zero, so it can be used to +distinguish between the two cases. +@end deftypevar + +@deftypevar {struct rwlock} diskfs_fsys_lock +Hold this lock while doing filesystem-level operations. Innocuous users +can just hold a reader lock, but operations that might corrupt other +threads should hold a writer lock. +@end deftypevar + +@deftypevar {volatile struct mapped_time_value *} diskfs_mtime +The current system time, as used by the diskfs routines. This is +converted into a @code{struct timeval} by the @code{maptime_read} +C library function (FIXME xref). +@end deftypevar + +@deftypevar int diskfs_synchronous +True if and only if we should do every operation synchronously. It +is the format-specific code's responsibility to keep allocation +information permanently in sync if this is set; the rest will +be done by format-independent code. +@end deftypevar + +@deftypefun error_t diskfs_set_sync_interval (@w{int @var{interval}}) +Establish a thread to sync the filesystem every @var{interval} seconds, +or never, if @var{interval} is zero. If an error occurs creating the +thread, it is returned, otherwise zero. Subsequent calls will create a +new thread and (eventually) get rid of the old one; the old thread won't +do any more syncs, regardless. +@end deftypefun + +@deftypevar spin_lock_t diskfs_node_refcnt_lock +Pager reference count lock. +@end deftypevar + +@deftypevar int diskfs_readonly +Set to zero if the filesystem is currently writable. +@end deftypevar + +@deftypefun error_t diskfs_set_readonly (@w{int @var{readonly}}) +Change an active filesystem between read-only and writable modes, +setting the global variable @var{diskfs_readonly} to reflect the current +mode. If an error is returned, nothing will have changed. +@var{diskfs_fsys_lock} should be held while calling this routine. +@end deftypefun + +@deftypefun int diskfs_check_readonly (void) +Check if the filesystem is readonly before an operation that writes it. +Return nonzero if readonly, otherwise zero. +@end deftypefun + +@deftypefun error_t diskfs_remount (void) +Reread all in-core data structures from disk. This function can only be +successful if @var{diskfs_readonly} is true. @var{diskfs_fsys_lock} +should be held while calling this routine. +@end deftypefun + +@deftypefun error_t diskfs_shutdown (@w{int @var{flags}}) +Shutdown the filesystem; @var{flags} are as for @code{fsys_shutdown}. +@end deftypefun + + +@node Diskfs Node Management +@comment node, Next, Prev , Up +@subsection Diskfs Node Management + +Every file or directory is a diskfs @dfn{node}. The following functions +help your diskfs callbacks manage nodes and their references: + +@deftypefun void diskfs_drop_node (@w{struct node *@var{np}}) +Node @var{np} now has no more references; clean all state. The +@var{diskfs_node_refcnt_lock} must be held, and will be released upon +return. @var{np} must be locked. +@end deftypefun + +@deftypefun void diskfs_node_update (@w{struct node *@var{np}}, @w{int @var{wait}}) +Set disk fields from @code{@var{np}->dn_stat}; update ctime, atime, and mtime +if necessary. If @var{wait} is true, then return only after the +physical media has been completely updated. +@end deftypefun + +@deftypefun void diskfs_nref (@w{struct node *@var{np}}) +Add a hard reference to node @var{np}. If there were no hard references +previously, then the node cannot be locked (because you must hold a hard +reference to hold the lock). +@end deftypefun + +@deftypefun void diskfs_nput (@w{struct node *@var{np}}) +Unlock node @var{np} and release a hard reference; if this is the last +hard reference and there are no links to the file then request light +references to be dropped. +@end deftypefun + +@deftypefun void diskfs_nrele (@w{struct node *@var{np}}) +Release a hard reference on @var{np}. If @var{np} 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 light references to be +dropped. +@end deftypefun + +@deftypefun void diskfs_nref_light (@w{struct node *@var{np}}) +Add a light reference to a node. +@end deftypefun + +@deftypefun void diskfs_nput_light (@w{struct node *@var{np}}) +Unlock node @var{np} and release a light reference. +@end deftypefun + +@deftypefun void diskfs_nrele_light (@w{struct node *@var{np}}) +Release a light reference on @var{np}. If @var{np} is locked by anyone, +then this cannot be the last reference (because you must hold a hard +reference in order to hold the lock). +@end deftypefun + +@deftypefun error_t diskfs_node_rdwr (@w{struct node *@var{np}}, @w{char *@var{data}}, @w{off_t @var{off}}, @w{size_t @var{amt}}, @w{int @var{direction}}, @w{struct protid *@var{cred}}, @w{size_t *@var{amtread}}) +This is called by other filesystem routines to read or write files, and +extends them automatically, if necessary. @var{np} is the node to be +read or written, and must be locked. @var{data} will be written or +filled. @var{off} identifies where in the file the I/O is to take place +(negative values are not allowed). @var{amt} is the size of @var{data} +and tells how much to copy. @var{dir} is zero for reading or nonzero +for writing. @var{cred} is the user doing the access (only used to +validate attempted file extension). For reads, @code{*@var{amtread}} is +filled with the amount actually read. +@end deftypefun + +@deftypefun void diskfs_notice_dirchange (@w{struct node *@var{dp}}, @w{enum dir_changed_type @var{type}}, @w{char *@var{name}}) +Send notifications to users who have requested them for directory +@var{dp} with @code{dir_notice_changes}. The type of modification and +affected name are @var{type} and @var{name} respectively. This should +be called by @code{diskfs_direnter}, @code{diskfs_dirremove}, +@code{diskfs_dirrewrite}, and anything else that changes the directory, +after the change is fully completed. +@end deftypefun + +@deftypefun {struct node *} diskfs_make_node (@w{struct disknode *@var{dn}}) +Create a new node structure with @var{ds} as its physical disknode. The +new node will have one hard reference and no light references. +@end deftypefun + +@c FIXME: It's odd that `hard' and `light' seem to be opposites when +@c we're talking about references. Or is `weak' the opposite of `hard'? +@c These terms need to be explained. +@c tb: hard is opposite to both light and weak, but we don't use both +@c tb: light and weak in the same context, so it's ok. + +These next node manipulation functions are not generally useful, but may +come in handy if you need to redefine any diskfs functions. + +@deftypefun error_t diskfs_create_node (@w{struct node *@var{dir}}, @w{char *@var{name}}, @w{mode_t @var{mode}}, @w{struct node **@var{newnode}}, @w{struct protid *@var{cred}}, @w{struct dirstat *@var{ds}}) +Create a new node. Give it @var{mode}: if @var{mode} includes +@code{IFDIR}, also initialize @file{.} and @file{..} in the new +directory. Return the node in @var{npp}. @var{cred} identifies the +user responsible for the call. If @var{name} is nonzero, then link the +new node into @var{dir} with name @var{name}; @var{ds} is the result of +a prior @code{diskfs_lookup} for creation (and @var{dir} has been held +locked since). @var{dir} must always be provided as at least a hint for +disk allocation strategies. +@end deftypefun + +@deftypefun void diskfs_set_node_times (@w{struct node *@var{np}}) +If @code{@var{np}->dn_set_ctime} is set, then modify +@code{@var{np}->dn_stat.st_ctime} appropriately; do the analogous +operations for atime and mtime as well. +@end deftypefun + +@deftypefun {struct node *} diskfs_check_lookup_cache (@w{struct node *@var{dir}}, @w{char *@var{name}}) +Scan the cache looking for @var{name} inside @var{dir}. If we don't +know any entries at all, then return zero. If the entry is confirmed to +not exist, then return -1. Otherwise, return @var{np} for the entry, +with a newly-allocated reference. +@end deftypefun + +@deftypefun error_t diskfs_cached_lookup (@w{int @var{cache_id}}, @w{struct node **@var{npp}}) +Return the node corresponding to @var{cache_id} in @code{*@var{npp}}. +@end deftypefun + +@deftypefun void diskfs_enter_lookup_cache (@w{struct node *@var{dir}}, @w{struct node *@var{np}}, @w{char *@var{name}}) +Node @var{np} has just been found in @var{dir} with @var{name}. If +@var{np} is null, that means that this name has been confirmed as absent +in the directory. +@end deftypefun + +@deftypefun void diskfs_purge_lookup_cache (@w{struct node *@var{dp}}, @w{struct node *@var{np}}) +Purge all references in the cache to @var{np} as a node inside directory +@var{dp}. +@end deftypefun + + +@node Diskfs Callbacks +@comment node, Next, Prev, Up +@subsection Diskfs Callbacks + +Like several other Hurd libraries, @code{libdiskfs} depends on you to +implement application-specific callback functions. You @emph{must} +define the following functions and variables, but you should also look +at @ref{Diskfs Options}, as there are several defaults which should be +modified to provide good filesystem support: + +@deftypevr {Structure} struct dirstat +You must define this type, which will hold information between a call to +@code{diskfs_lookup} and a call to one of @code{diskfs_direnter}, +@code{diskfs_dirremove}, or @code{diskfs_dirrewrite}. It must contain +enough information so that those calls work as described below. +@end deftypevr + +@deftypevar const size_t diskfs_dirstat_size +This must be the size in bytes of a @code{struct dirstat}. +@end deftypevar + +@deftypevar int diskfs_link_max +This is the maximum number of links to any one file, which must be a +positive integer. The implementation of @code{dir_rename} does not know +how to succeed if this is only one allowed link; on such formats you +need to reimplement @code{dir_rename} yourself. +@end deftypevar + +@deftypevar int diskfs_maxsymlinks +This variable is a positive integer which is the maximum number of +symbolic links which can be traversed within a single call to +@code{dir_lookup}. If this is exceeded, @code{dir_lookup} will +return @code{ELOOP}. +@end deftypevar + +@deftypevar {struct node *} diskfs_root_node +Set this to be the node of the root of the filesystem. +@end deftypevar + +@deftypevar {char *} diskfs_server_name +Set this to the name of the filesystem server. +@end deftypevar + +@deftypevar {char *} diskfs_server_version +Set this to be the server version string. +@end deftypevar + +@deftypevar {char *} diskfs_disk_name +This should be a string that somehow identifies the particular disk this +filesystem is interpreting. It is generally only used to print messages +or to distinguish instances of the same filesystem type from one +another. If this filesystem accesses no external media, then define +this to be zero. +@end deftypevar + +@deftypefun error_t diskfs_set_statfs (@w{fsys_statfsbuf_t *@var{statfsbuf}}) +Set @code{*@var{statfsbuf}} with appropriate values to reflect the +current state of the filesystem. +@end deftypefun + +@deftypefun error_t diskfs_lookup (@w{struct node *@var{dp}}, @w{char *@var{name}}, @w{enum lookup_type @var{type}}, @w{struct node **@var{np}}, @w{struct dirstat *@var{ds}}, @w{struct protid *@var{cred}}) +@deftypefunx error_t diskfs_lookup_hard (@w{struct node *@var{dp}}, @w{char *@var{name}}, @w{enum lookup_type @var{type}}, @w{struct node **@var{np}}, @w{struct dirstat *@var{ds}}, @w{struct protid *@var{cred}}) +You should not define @code{diskfs_lookup}, because it is simply a +wrapper for @code{diskfs_lookup_hard}, and is already defined in +@code{libdiskfs}. + +Lookup in directory @var{dp} (which is locked) the name @var{name}. +@var{type} will either be @code{LOOKUP}, @code{CREATE}, @code{RENAME}, +or @code{REMOVE}. @var{cred} identifies the user making the call. + +If the name is found, return zero, and (if @var{np} is nonzero) set +@code{*@var{np}} to point to the node for it, which should be locked. +If the name is not found, return @code{ENOENT}, and (if @var{np} is +nonzero) set @code{*@var{np}} to zero. If @var{np} is zero, then the +node found must not be locked, not even transitorily. Lookups for +@code{REMOVE} and @code{RENAME} (which must often check permissions on +the node being found) will always set @var{np}. + +If @var{ds} is nonzero then the behaviour varies depending on the +requested lookup @var{type}: + +@table @code +@item LOOKUP +Set @code{*@var{ds}} to be ignored by @code{diskfs_drop_dirstat} + +@item CREATE +On success, set @code{*@var{ds}} to be ignored by +@code{diskfs_drop_dirstat}. @* +On failure, set @code{*@var{ds}} for a future call to +@code{diskfs_direnter}. + +@item RENAME +On success, set @code{*@var{ds}} for a future call to +@code{diskfs_dirrewrite}. @* +On failure, set @code{*@var{ds}} for a future call to +@code{diskfs_direnter}. + +@item REMOVE +On success, set @code{*@var{ds}} for a future call to +@code{diskfs_dirremove}. @* +On failure, set @code{*@var{ds}} to be ignored by +@code{diskfs_drop_dirstat}. +@end table + +The caller of this function guarantees that if @var{ds} is nonzero, then +either the appropriate call listed above or @code{diskfs_drop_dirstat} +will be called with @var{ds} before the directory @var{dp} is unlocked, +and guarantees that no lookup calls will be made on this directory +between this lookup and the use (or destruction) of *DS. + +If you use the library's versions of @code{diskfs_rename_dir}, +@code{diskfs_clear_directory}, and @code{diskfs_init_dir}, then lookups +for @file{..} might have the flag @code{SPEC_DOTDOT} ORed in. This has a +special meaning depending on the requested lookup @var{type}: + +@table @code +@item LOOKUP +@var{dp} should be unlocked and its reference dropped before returning. + +@item CREATE +Ignore this case, because @code{SPEC_DOTDOT} is guaranteed not to be +given. + +@item RENAME +@itemx REMOVE +In both of these cases, the node being found (@code{*@var{np}}) is +already held locked, so don't lock it or add a reference to it. +@end table + +Return @code{ENOENT} if @var{name} isn't in the directory. Return +@code{EAGAIN} if @var{name} refers to the @file{..} of this filesystem's +root. Return @code{EIO} if appropriate. +@end deftypefun + +@deftypefun error_t diskfs_direnter (@w{struct node *@var{dp}}, @w{char *@var{name}}, @w{struct node *@var{np}}, @w{struct dirstat *@var{ds}}, @w{struct protid *@var{cred}}) +@deftypefunx error_t diskfs_direnter_hard (@w{struct node *@var{dp}}, @w{char *@var{name}}, @w{struct node *@var{np}}, @w{struct dirstat *@var{ds}}, @w{struct protid *@var{cred}}) +You should not define @code{diskfs_direnter}, because it is simply a +wrapper for @code{diskfs_direnter_hard}, and is already defined in +@code{libdiskfs}. + +Add @var{np} to directory @var{dp} under the name @var{name}. This will +only be called after an unsuccessful call to @code{diskfs_lookup} of type +@code{CREATE} or @code{RENAME}; @var{dp} has been locked continuously +since that call and @var{ds} is as that call set it, @var{np} is locked. +@var{cred} identifies the user responsible for the call (to be used only +to validate directory growth). +@end deftypefun + +@deftypefun error_t diskfs_dirrewrite (@w{struct node *@var{dp}}, @w{struct node *@var{oldnp}}, @w{struct node *@var{np}}, @w{char *@var{name}}, @w{struct dirstat *@var{ds}}) +@deftypefunx error_t diskfs_dirrewrite_hard (@w{struct node *@var{dp}}, @w{struct node *@var{np}}, @w{struct dirstat *@var{ds}}) +You should not define @code{diskfs_dirrewrite}, because it is simply a +wrapper for @code{diskfs_dirrewrite_hard}, and is already defined in +@code{libdiskfs}. + +This will only be called after a successful call to @code{diskfs_lookup} +of type @code{RENAME}; this call should change the name found in +directory @var{dp} to point to node @var{np} instead of its previous +referent. @var{dp} has been locked continuously since the call to +@code{diskfs_lookup} and @var{ds} is as that call set it; @var{np} is +locked. + +@code{diskfs_dirrewrite} has some additional specifications: @var{name} +is the name within @var{dp} which used to correspond to the previous +referent, @var{oldnp}; it is this reference which is being rewritten. +@code{diskfs_dirrewrite} also calls @code{diskfs_notice_dirchange} if +@code{@var{dp}->dirmod_reqs} is nonzero. +@end deftypefun + +@deftypefun error_t diskfs_dirremove (@w{struct node *@var{dp}}, @w{struct node *@var{np}}, @w{char *@var{name}}, @w{struct dirstat *@var{ds}}) +@deftypefunx error_t diskfs_dirremove_hard (@w{struct node *@var{dp}}, @w{struct dirstat *@var{ds}}) +You should not define @code{diskfs_dirremove}, because it is simply a +wrapper for @code{diskfs_dirremove_hard}, and is already defined in +@code{libdiskfs}. + +This will only be called after a successful call to @code{diskfs_lookup} +of type @code{REMOVE}; this call should remove the name found from the +directory @var{ds}. @var{dp} has been locked continuously since the +call to @code{diskfs_lookup} and @var{ds} is as that call set it. + +@code{diskfs_dirremove} has some additional specifications: this routine +should call @code{diskfs_notice_dirchange} if +@code{@var{dp}->dirmod_reqs} is nonzero. The entry being removed has +name @var{name} and refers to @var{np}. +@end deftypefun + +@deftypefun error_t diskfs_drop_dirstat (@w{struct node *@var{dp}}, @w{struct dirstat *@var{ds}}) +@var{ds} has been set by a previous call to @code{diskfs_lookup} on +directory @var{dp}; this function is guaranteed to be called if +@code{diskfs_direnter}, @code{diskfs_dirrewrite}, and +@code{diskfs_dirremove} have not been called, and should free any state +retained by a @code{struct dirstat}. @var{dp} has been locked +continuously since the call to @code{diskfs_lookup}. +@end deftypefun + +@deftypefun void diskfs_null_dirstat (@w{struct dirstat *@var{ds}}) +Initialize @var{ds} such that @code{diskfs_drop_dirstat} will ignore it. +@end deftypefun + +@deftypefun error_t diskfs_get_directs (@w{struct node *@var{dp}}, @w{int @var{entry}}, @w{int @var{n}}, @w{char **@var{data}}, @w{u_int *@var{datacnt}}, @w{vm_size_t @var{bufsiz}}, @w{int *@var{amt}}) +Return @var{n} directory entries starting at @var{entry} from locked +directory node @var{dp}. Fill @code{*@var{data}} with the entries; +which currently points to @code{*@var{datacnt}} bytes. If it isn't big +enough, @code{vm_allocate} into @code{*@var{data}}. Set +@code{*@var{datacnt}} with the total size used. Fill @var{amt} with the +number of entries copied. Regardless, never copy more than @var{bufsiz} +bytes. If @var{bufsiz} is zero, then there is no limit on +@code{*@var{datacnt}}; if @var{n} is -1, then there is no limit on +@var{amt}. +@end deftypefun + +@deftypefun int diskfs_dirempty (@w{struct node *@var{dp}}, @w{struct protid *@var{cred}}) +Return nonzero if locked directory @var{dp} is empty. If the user has +not redefined @code{diskfs_clear_directory} and +@code{diskfs_init_directory}, then `empty' means `only possesses entries +labelled @file{.} and @file{..}. @var{cred} identifies the user making +the call@dots{} if this user cannot search the directory, then this +routine should fail. +@end deftypefun + +@deftypefun error_t diskfs_get_translator (@w{struct node *@var{np}}, @w{char **@var{namep}}, @w{u_int *@var{namelen}}) +For locked node @var{np} (for which @code{diskfs_node_translated} is +true) look up the name of its translator. Store the name into newly +malloced storage and set @code{*@var{namelen}} to the total length. +@end deftypefun + +@deftypefun error_t diskfs_set_translator (@w{struct node *@var{np}}, @w{char *@var{name}}, @w{u_int @var{namelen}}, @w{struct protid *@var{cred}}) +For locked node @var{np}, set the name of the translating program to be +@var{name}, which is @var{namelen} bytes long. @var{cred} identifies +the user responsible for the call. +@end deftypefun + +@deftypefun error_t diskfs_truncate (@w{struct node *@var{np}}, @w{off_t @var{size}}) +Truncate locked node @var{np} to be @var{size} bytes long. If @var{np} +is already less than or equal to @var{size} bytes long, do nothing. If +this is a symlink (and @code{diskfs_shortcut_symlink} is set) then this +should clear the symlink, even if @code{diskfs_create_symlink_hook} +stores the link target elsewhere. +@end deftypefun + +@deftypefun error_t diskfs_grow (@w{struct node *@var{np}}, @w{off_t @var{size}}, @w{struct protid *@var{cred}}) +Grow the disk allocated to locked node @var{np} to be at least +@var{size} bytes, and set @code{@var{np}->allocsize} to the actual +allocated size. If the allocated size is already @var{size} bytes, do +nothing. @var{cred} identifies the user responsible for the call. +@end deftypefun + +@deftypefun error_t diskfs_node_reload (@w{struct node *@var{node}}) +This function must reread all data specific to @var{node} from disk, +without writing anything. It is always called with +@var{diskfs_readonly} set to true. +@end deftypefun + +@deftypefun error_t diskfs_reload_global_state (void) +This function must invalidate all cached global state, and reread it as +necessary from disk, without writing anything. It is always called with +@var{diskfs_readonly} set to true. @code{diskfs_node_reload} is +subsequently called on all active nodes, so this call doesn't need to +reread any node-specific data. +@end deftypefun + +@deftypefun error_t diskfs_node_iterate (error_t (*@var{fun}) (@w{struct node *@var{np}})) +For each active node @var{np}, call @var{fun}. The node is to be locked +around the call to @var{fun}. If @var{fun} returns nonzero for any +node, then stop immediately, and return that value. +@end deftypefun + +@deftypefun error_t diskfs_alloc_node (@w{struct node *@var{dp}}, @w{mode_t @var{mode}}, @w{struct node **@var{np}}) +Allocate a new node to be of mode @var{mode} in locked directory +@var{dp}, but don't actually set the mode or modify the directory, since +that will be done by the caller. The user responsible for the request +can be identified with @var{cred}. Set @code{*@var{np}} to be the newly +allocated node. +@end deftypefun + +@deftypefun void diskfs_free_node (@w{struct node *@var{np}}, @w{mode_t @var{mode}}) +Free node @var{np}; the on-disk copy has already been synchronized with +@code{diskfs_node_update} (where @code{@var{np}->dn_stat.st_mode} was +zero). @var{np}'s mode used to be @var{mode}. +@end deftypefun + +@deftypefun void diskfs_lost_hardrefs (@w{struct node *@var{np}}) +Locked node @var{np} has some light references but has just lost its +last hard reference. +@end deftypefun + +@deftypefun void diskfs_new_hardrefs (@w{struct node *@var{np}}) +Locked node @var{np} has just acquired a hard reference where it had +none previously. Therefore, it is okay again to have light references +without real users. +@end deftypefun + +@deftypefun void diskfs_try_dropping_softrefs (@w{struct node *@var{np}}) +Node @var{np} has some light references, but has just lost its last hard +references. Take steps so that if any light references can be freed, +they are. Both @var{diskfs_node_refcnt_lock} and @var{np} are locked. +This function will be called after @code{diskfs_lost_hardrefs}. +@end deftypefun + +@deftypefun void diskfs_node_norefs (@w{struct node *@var{np}}) +Node @var{np} has no more references; free local state, including +@code{*@var{np}} if it shouldn't be retained. +@var{diskfs_node_refcnt_lock} is held. +@end deftypefun + +@deftypefun error_t diskfs_set_hypermetadata (@w{int @var{wait}}, @w{int @var{clean}}) +Write any non-paged metadata from format-specific buffers to disk, +asynchronously unless @var{wait} is nonzero. If @var{clean} is nonzero, +then after this is written the filesystem will be absolutely clean, and +it must be possible for the non-paged metadata to indicate that fact. +@end deftypefun + +@deftypefun void diskfs_write_disknode (@w{struct node *@var{np}}, @w{int @var{wait}}) +Write the information in @code{@var{np}->dn_stat} and any associated +format-specific information to the disk. If @var{wait} is true, then +return only after the physical media has been completely updated. +@end deftypefun + +@deftypefun void diskfs_file_update (@w{struct node *@var{np}}, @w{int @var{wait}}) +Write the contents and all associated metadata of file NP to disk. +Generally, this will involve calling @code{diskfs_node_update} for much +of the metadata. If @var{wait} is true, then return only after the +physical media has been completely updated. +@end deftypefun + +@deftypefun mach_port_t diskfs_get_filemap (@w{struct node *@var{np}}, @w{vm_prot_t @var{prot}}) +Return a memory object port (send right) for the file contents of +@var{np}. @var{prot} is the maximum allowable access. On errors, +return @code{MACH_PORT_NULL} and set @code{errno}. +@end deftypefun + +@deftypefun {struct pager *} diskfs_get_filemap_pager_struct (@w{struct node *@var{np}}) +Return a @code{struct pager *} that refers to the pager returned by +diskfs_get_filemap for locked node NP, suitable for use as an argument +to @code{pager_memcpy}. +@end deftypefun + +@deftypefun vm_prot_t diskfs_max_user_pager_prot (void) +Return the bitwise OR of the maximum @code{prot} parameter (the second +argument to @code{diskfs_get_filemap}) for all active user pagers. +@end deftypefun + +@deftypefun int diskfs_pager_users (void) +Return nonzero if there are pager ports exported that might be in use by +users. Further pager creation should be blocked before this function +returns zero. +@end deftypefun + +@deftypefun void diskfs_sync_everything (@w{int @var{wait}}) +Sync all the pagers and write any data belonging on disk except for the +hypermetadata. If @var{wait} is true, then return only after the +physical media has been completely updated. +@end deftypefun + +@deftypefun void diskfs_shutdown_pager (void) +Shut down all pagers. This is irreversible, and is done when the +filesystem is exiting. +@end deftypefun + + +@node Diskfs Options +@comment node, Next, Prev, Up +@subsection Diskfs Options + +The functions and variables described in this subsection already have +default definitions in @code{libdiskfs}, so you are not forced to define +them; rather, they may be redefined on a case-by-case basis. + +You should set the values of any option variables as soon as your program +starts (before you make any calls to diskfs, such as argument parsing). + +@deftypevar int diskfs_hard_readonly +You should set this variable to nonzero if the filesystem media can +never be made writable. +@end deftypevar + +@deftypevar {char *} diskfs_extra_version +Set this to be any additional version specification that should be +printed for --version. +@end deftypevar + +@deftypevar int diskfs_shortcut_symlink +This should be nonzero if and only if the filesystem format supports +shortcutting symbolic link translation. The library guarantees that +users will not be able to read or write the contents of the node +directly, and the library will only do so if the symlink hook functions +(@code{diskfs_create_symlink_hook} and @code{diskfs_read_symlink_hook}) +return @code{EINVAL} or are not defined. The library knows that the +@code{dn_stat.st_size} field is the length of the symlink, even if the +hook functions are used. +@end deftypevar + +@deftypevar int diskfs_shortcut_chrdev +@deftypevarx int diskfs_shortcut_blkdev +@deftypevarx int diskfs_shortcut_fifo +@deftypevarx int diskfs_shortcut_ifsock +These variables should be nonzero if and only if the filesystem format +supports shortcutting character device node, block device node, FIFO, or +Unix-domain socket translation, respectively. +@end deftypevar + +@deftypevar int diskfs_default_sync_interval +@code{diskfs_set_sync_interval} is called with this value when the first +diskfs thread is started up (in @code{diskfs_spawn_first_thread}). This +variable has a default default value of 30, which causes disk buffers to +be flushed at least every 30 seconds. +@end deftypevar + +@deftypefun error_t diskfs_validate_mode_change (@w{struct node *@var{np}}, @w{mode_t @var{mode}}) +@deftypefunx error_t diskfs_validate_owner_change (@w{struct node *@var{np}}, @w{uid_t @var{uid}}) +@deftypefunx error_t diskfs_validate_group_change (@w{struct node *@var{np}}, @w{gid_t @var{gid}}) +@deftypefunx error_t diskfs_validate_author_change (@w{struct node *@var{np}}, @w{uid_t @var{author}}) +@deftypefunx error_t diskfs_validate_flags_change (@w{struct node *@var{np}}, @w{int @var{flags}}) +@deftypefunx error_t diskfs_validate_rdev_change (@w{struct node *@var{np}}, @w{dev_t @var{rdev}}) +Return zero if for the node @var{np} can be changed as requested. That +is, if @var{np}'s mode can be changed to @var{mode}, owner to @var{uid}, +group to @var{gid}, author to @var{author}, flags to @var{flags}, or raw +device number to @var{rdev}, respectively. Otherwise, return an error +code. + +It must always be possible to clear the mode or the flags; diskfs will +not ask for permission before doing so. +@end deftypefun + +@deftypefun void diskfs_readonly_changed (@w{int @var{readonly}}) +This is called when the disk has been changed from read-only to +read-write mode or vice-versa. @var{readonly} is the new state (which +is also reflected in @var{diskfs_readonly}). This function is also +called during initial startup if the filesystem is to be writable. +@end deftypefun + +@deftypefn {Variable} {error_t (*} diskfs_create_symlink_hook ) (@w{struct node *@var{np}}, @w{char *@var{target}}) +If this function pointer is nonzero (and @code{diskfs_shortcut_symlink} +is set) it is called to set a symlink. If it returns @code{EINVAL} or +isn't set, then the normal method (writing the contents into the file +data) is used. If it returns any other error, it is returned to the +user. +@end deftypefn + +@deftypefn {Variable} {error_t (*} diskfs_read_symlink_hook ) (@w{struct node *@var{np}}, @w{char *@var{target}}) +If this function pointer is nonzero (and @code{diskfs_shortcut_symlink} +is set) it is called to read the contents of a symlink. If it returns +@code{EINVAL} or isn't set, then the normal method (reading from the +file data) is used. If it returns any other error, it is returned to +the user. +@end deftypefn + +@deftypefun error_t diskfs_rename_dir (@w{struct node *@var{fdp}}, @w{struct node *@var{fnp}}, @w{char *@var{fromname}}, @w{struct node *@var{tdp}}, @w{char *@var{toname}}, @w{struct protid *@var{fromcred}}, @w{struct protid *@var{tocred}}) +Rename directory node @var{fnp} (whose parent is @var{fdp}, and which +has name @var{fromname} in that directory) to have name @var{toname} +inside directory @var{tdp}. None of these nodes are locked, and none +should be locked upon return. This routine is serialized, so it doesn't +have to be reentrant. Directories will never be renamed except by this +routine. @var{fromcred} is the user responsible for @var{fdp} and +@var{fnp}. @var{tocred} is the user responsible for @var{tdp}. This +routine assumes the usual convention where @file{.} and @file{..} are +represented by ordinary links; if that is not true for your format, you +have to redefine this function. +@end deftypefun + +@deftypefun error_t diskfs_clear_directory (@w{struct node *@var{dp}}, @w{struct node *@var{pdp}}, @w{struct protid *@var{cred}}) +Clear the @file{.} and @file{..} entries from directory @var{dp}. Its +parent is @var{pdp}, and the user responsible for this is identified by +@var{cred}. Both directories must be locked. This routine assumes the +usual convention where @file{.} and @file{..} are represented by +ordinary links; if that is not true for your format, you have to +redefine this function. +@end deftypefun + +@deftypefun error_t diskfs_init_dir (@w{struct node *@var{dp}}, @w{struct node *@var{pdp}}, @w{struct protid *@var{cred}}) +Locked node @var{dp} is a new directory; add whatever links are +necessary to give it structure; its parent is the (locked) node +@var{pdp}. This routine may not call @code{diskfs_lookup} on @var{pdp}. +The new directory must be clear within the meaning of +@code{diskfs_dirempty}. This routine assumes the usual convention where +@file{.} and @file{..} are represented by ordinary links; if that is not +true for your format, you have to redefine this function. @var{cred} +identifies the user making the call. +@end deftypefun + + +@node Diskfs Internals +@comment node, Next, Prev, Up +@subsection Diskfs Internals + +The library also exports the following functions, but they are not +generally useful unless you are redefining other functions the library +provides. + +@deftypefun error_t diskfs_create_protid (@w{struct peropen *@var{po}}, @w{struct iouser *@var{user}}, @w{struct protid **@var{cred}}) +Create and return a protid for an existing peropen @var{po} in +@var{cred}, referring to user @var{user}. The node @code{@var{po}->np} +must be locked. +@end deftypefun + +@deftypefun error_t diskfs_start_protid (@w{struct peropen *@var{po}}, @w{struct protid **@var{cred}}) +Build and return in @var{cred} a protid which has no user +identification, for peropen @var{po}. The node @code{@var{po}->np} must +be locked. +@end deftypefun + +@deftypefun void diskfs_finish_protid (@w{struct protid *@var{cred}}, @w{struct iouser *@var{user}}) +Finish building protid @var{cred} started with @code{diskfs_start_protid}; +the user to install is @var{user}. +@end deftypefun + +@deftypefun void diskfs_protid_rele (@w{void *@var{arg}}) +Called when a protid @var{cred} has no more references. Because +references to protids are maintained by the port management library, +this is installed in the clean routines list. The ports library will +free the structure. +@end deftypefun + +@deftypefun {struct peropen *} diskfs_make_peropen (@w{struct node *@var{np}}, @w{int @var{flags}}, @w{struct peropen *@var{context}}) +Create and return a new peropen structure on node @var{np} with open +flags @var{flags}. The initial values for the @code{root_parent}, +@code{shadow_root}, and @code{shadow_root_parent} fields are copied from +@var{context} if it is nonzero, otherwise each of these values are +set to zero. +@end deftypefun + +@deftypefun void diskfs_release_peropen (@w{struct peropen *@var{po}}) +Decrement the reference count on @var{po}. +@end deftypefun + +@deftypefun error_t diskfs_execboot_fsys_startup (@w{mach_port_t @var{port}}, @w{int @var{flags}}, @w{mach_port_t @var{ctl}}, @w{mach_port_t *@var{real}}, @w{mach_msg_type_name_t *@var{realpoly}}) +This function is called by @code{S_fsys_startup} for execserver +bootstrap. The execserver is able to function without a real node, +hence this fraud. Arguments are as for @code{fsys_startup} in +@code{<hurd/fsys.defs>}. +@end deftypefun + +@deftypefun int diskfs_demuxer (@w{mach_msg_header_t *@var{inp}}, @w{mach_msg_header_t *@var{outp}}) +Demultiplex incoming @code{libports} messages on diskfs ports. +@end deftypefun + +@findex diskfs_S_* +The diskfs library also provides functions to demultiplex the fs, io, +fsys, interrupt, and notify interfaces. All the server routines have +the prefix @code{diskfs_S_}. For those routines, @code{in} arguments of +type @code{file_t} or @code{io_t} appear as @code{struct protid *} to +the stub. + + + +@node Fshelp Library +@comment node, Next, Prev, Up +@section Fshelp Library +@scindex libfshelp +@scindex fshelp.h + +The fshelp library implements various things that are useful to most +implementors of the file protocol. It presumes that you are using the +iohelp library as well. @code{libfshelp} is divided into separate +facilities which may be used independently. These functions are +declared in @code{<hurd/fshelp.h>}. +@c FIXME: perhaps `useful to most implementors' should read `generic +@c to most implementations' + +@menu +* Passive Translator Linkage:: Invoking passive translators. +* Active Translator Linkage:: Managing active translators. +* Fshelp Locking:: Implementing file locking. +* Fshelp Permissions:: Standard file access permission policies. +* Fshelp Misc:: Useful standalone routines. +@end menu + +@node Passive Translator Linkage +@comment node, Next, Prev, Up +@subsection Passive Translator Linkage + +These routines are self-contained and start passive translators, +returning the control port. They do not require multithreading or the +ports library. + +@deftypefn {Typedef} {typedef error_t (*} fshelp_open_fn_t ) (@w{int @var{flags}}, @w{file_t *@var{node}}, @w{mach_msg_type_name_t *@var{node_type}}) +A callback used by the translator starting functions. +Given some open flags, opens the appropriate file, and +returns the node port. +@end deftypefn + +@deftypefun error_t fshelp_start_translator_long (@w{fshelp_open_fn_t @var{underlying_open_fn}}, @w{char *@var{name}}, @w{char *@var{argz}}, @w{int @var{argz_len}}, @w{mach_port_t *@var{fds}}, @w{mach_msg_type_name_t @var{fds_type}}, @w{int @var{fds_len}}, @w{mach_port_t *@var{ports}}, @w{mach_msg_type_name_t @var{ports_type}}, @w{int @var{ports_len}}, @w{int *@var{ints}}, @w{int @var{ints_len}}, @w{int @var{timeout}}, @w{fsys_t *@var{control}}) +Start a passive translator @var{name} with arguments @var{argz} (length +@var{argz_len}). Initialize the initports to @var{ports} (length +@var{ports_len}), the initints to @var{ints} (length @var{ints_len}), +and the file descriptor table to @var{fds} (length @var{fds_len}). +Return the control port in @code{*@var{control}}. If the translator doesn't +respond or die in @var{timeout} milliseconds (if @var{timeout} is +greater than zero), return an appropriate error. If the translator dies +before responding, return @code{EDIED}. +@end deftypefun + +@deftypefun error_t fshelp_start_translator (@w{fshelp_open_fn_t @var{underlying_open_fn}}, @w{char *@var{name}}, @w{char *@var{argz}}, @w{int @var{argz_len}}, @w{int @var{timeout}}, @w{fsys_t *@var{control}}) +Same as @code{fshelp_start_translator_long}, except the initports and +ints are copied from our own state, @var{fd}[2] is copied from our own +stderr, and the other fds are cleared. For full-service filesystems, it +is almost always wrong to use @code{fshelp_start_translator}, because +the current working directory of the translator will not then be as +normally expected. (Current working directories of passive translators +should be the directory they were found in.) In fact, full-service +filesystems should usually start passive translators as a side-effect of +calling @code{fshelp_fetch_root} (@pxref{Active Translator Linkage}). +@end deftypefun + +@node Active Translator Linkage +@comment node, Next, Prev, Up +@subsection Active Translator Linkage + +These routines implement the linkage to active translators needed +by any filesystem which supports them. They require the threads +library and use the passive translator routines above, but they don't +require the ports library at all. + +This interface is complex, because creating the ports and state +necessary for @code{start_translator_long} is expensive. The caller to +@code{fshelp_fetch_root} should not need to create them on every call, +since usually there will be an existing active translator. + +@deftypefun void fshelp_transbox_init (@w{struct transbox *@var{transbox}}, @w{struct mutex *@var{lock}}, @w{void *@var{cookie}}) +Initialize a transbox, which contains state information for active +translators. +@end deftypefun + +@deftypefn {Typedef} {typedef error_t (*} fshelp_fetch_root_callback1_t ) (@w{void *@var{cookie1}}, @w{void *@var{cookie2}}, @w{uid_t *@var{uid}}, @w{gid_t *@var{gid}}, @w{char **@var{argz}}, @w{size_t *@var{argz_len}}) +This routine is called by @code{fshelp_fetch_root} to fetch more +information. Return the owner and group of the underlying translated +file in @code{*@var{uid}} and @code{*@var{gid}}; point +@code{*@var{argz}} at the entire passive translator specification for +the file (setting @code{*@var{argz_len}} to the length). If there is no +passive translator, then return @code{ENOENT}. @var{cookie1} is the +cookie passed in @code{fshelp_transbox_init}. @var{cookie2} is the +cookie passed in the call to @code{fshelp_fetch_root}. +@end deftypefn + +@deftypefn {Typedef} {typedef error_t (*} fshelp_fetch_root_callback2_t ) (@w{void *@var{cookie1}}, @w{void *@var{cookie2}}, @w{int @var{flags}}, @w{mach_port_t *@var{underlying}}, @w{mach_msg_type_name_t *@var{underlying_type}}) +This routine is called by @code{fshelp_fetch_root} to fetch more +information. Return an unauthenticated node for the file itself in +@code{*@var{underlying}} and @code{*@var{underlying_type}} (opened with +@var{flags}). @var{cookie1} is the cookie passed in +@code{fshelp_transbox_init}. @var{cookie2} is the cookie passed in the +call to @code{fshelp_fetch_root}. +@end deftypefn + +@deftypefun error_t fshelp_fetch_root (@w{struct transbox *@var{transbox}}, @w{void *@var{cookie}}, @w{file_t @var{dotdot}}, @w{struct iouser *@var{user}}, @w{int @var{flags}}, @w{fshelp_fetch_root_callback1_t @var{callback1}}, @w{fshelp_fetch_root_callback2_t @var{callback2}}, @w{retry_type *@var{retry}}, @w{char *@var{retryname}}, @w{mach_port_t *@var{root}}) +Fetch the root from @var{transbox}. @var{dotdot} is an unauthenticated +port for the directory in which we are looking; @var{user} specifies the +ids of the user responsible for the call. @var{flags} are as for +@code{dir_lookup} (but @code{O_CREAT} and @code{O_EXCL} are not +meaningful and are ignored). The transbox lock (as set by +@code{fshelp_transbox_init}) must be held before the call, and will be +held upon return, but may be released during the operation of the call. +@end deftypefun + +@deftypefun int fshelp_translated (@w{struct transbox *@var{box}}) +Return true if and only if there is an active translator on this box. +@end deftypefun + +@deftypefun error_t fshelp_set_active (@w{struct transbox *@var{box}}, @w{fsys_t @var{newactive}}, @w{int @var{excl}}) +Atomically replace the existing active translator port for this box with +@var{newactive}. If @var{excl} is non-zero then don't modify an +existing active transbox; return @code{EBUSY} instead. +@end deftypefun + +@deftypefun error_t fshelp_fetch_control (@w{struct transbox *@var{box}}, @w{mach_port_t *@var{control}}) +Fetch the control port to make a request on it. It's a bad idea to use +@code{fsys_getroot} with the result; use @code{fshelp_fetch_root} +instead. +@end deftypefun + +@deftypefun void fshelp_drop_transbox (@w{struct transbox *@var{box}}) +Clean transbox state so that deallocation or reuse is possible. +@end deftypefun + + +@node Fshelp Locking +@comment node, Next, Prev +@subsection Fshelp Locking + +The @code{flock} call is in flux, as the current Hurd interface (as of +version @value{VERSION}) is not suitable for implementing the POSIX +record-locking semantics. + + +@node Fshelp Permissions +@comment node, Next, Prev , Up +@subsection Fshelp Permissions + +These functions are designed to aid with user permission checking. It +is a good idea to use these routines rather than to roll your own, so +that Hurd users see consistent handling of file and directory permission +bits. + +@deftypefun error_t fshelp_isowner (@w{struct stat *@var{st}}, @w{struct iouser *@var{user}}) +Check to see whether @var{user} should be considered the owner of the +file identified by @var{st}. If so, return zero; otherwise return an +appropriate error code. +@end deftypefun + +@deftypefun error_t fshelp_access (@w{struct stat *@var{st}}, @w{int @var{op}}, @w{struct iouser *@var{user}}) +Check to see whether the user @var{user} can operate on the file +identified by @var{st}. @var{op} is one of @code{S_IREAD}, +@code{S_IWRITE}, and @code{S_IEXEC}. If the access is permitted, return +zero; otherwise return an appropriate error code. +@end deftypefun + +@deftypefun error_t fshelp_checkdirmod (@w{struct stat *@var{dir}}, @w{struct stat *@var{st}}, @w{struct iouser *@var{user}}) +Check to see whether @var{user} is allowed to modify @var{dir} with respect to +existing file @var{st}. If there is no existing file, then @var{st} +should be set to zero. If the access is permissible, return zero; +otherwise return an appropriate error code. +@c FIXME: what does it mean to modify a directory with respect to an +@c existing file? +@c tb: If you delete a file, say, then you are modifying the directory +@c tb: (not the file) but with respect to that file. This is relevant +@c tb: in implementing the directory sticky-bit permissions algorithm. +@end deftypefun + +@node Fshelp Misc +@comment node, Next, Prev, Up +@subsection Fshelp Misc + +The following functions are completely standalone: + +@deftypefun error_t fshelp_delegate_translation (@w{char *@var{server_name}}, @w{mach_port_t @var{requestor}}, @w{char **@var{argv}}) +Try to hand off responsibility from a translator to the server located +on the node @var{server_name}. @var{requestor} is the translator's +bootstrap port, and @var{argv} is the command line. If +@var{server_name} is null, then a name is concocted by prepending +@code{_servers} to @code{argv[0]} . +@end deftypefun + +@deftypefun error_t fshelp_exec_reauth (@w{int @var{suid}}, @w{uid_t @var{uid}}, @w{int @var{sgid}}, @w{gid_t @var{gid}}, @w{auth_t @var{auth}}, error_t (*@var{get_file_ids}) (@w{struct idvec *@var{uids}}, @w{struct idvec *@var{gids}}), @w{mach_port_t *@var{ports}}, @w{mach_msg_type_number_t @var{num_ports}}, @w{mach_port_t *@var{fds}}, @w{mach_msg_type_number_t @var{num_fds}}, @w{int *@var{secure}}) +If @var{suid} or @var{sgid} is true, adds @var{uid} and/or @var{gid} +respectively to the authentication in +@code{@var{ports}[INIT_PORT_AUTH]}, and replaces it with the result. +All the other ports in @var{ports} and @var{fds} are then +reauthenticated, using any privileges available through @var{auth}. If +the auth port in @code{@var{ports}[INIT_PORT_AUTH]} is bogus, and +@var{get_file_ids} is non-null, it is called to get a list +of uids and gids from the file to use as a replacement. If @var{secure} +is non-null and any added ids are new, then the variable it points to is +set to nonzero, otherwise zero. If either the uid or gid case fails, +then the other may still apply. +@end deftypefun + +@deftypefun error_t fshelp_get_identity (@w{struct port_bucket *@var{bucket}}, @w{ino_t @var{fileno}}, @w{mach_port_t *@var{pt}}) +Return an identity port in @code{*@var{pt}} for the node numbered +@var{fileno}, suitable for returning from @code{io_identity}; exactly +one send right must be created from the returned value. @var{fileno} +should be the same value returned as the @var{fileno} out-parameter in +@code{io_identity}, and in the enclosing directory (except for mount +points), and in the @code{st_ino} stat field. @var{bucket} should be a +@code{libports} port bucket; fshelp requires the caller to make sure +port operations (for no-senders notifications) are used. +@end deftypefun + +@deftypefun error_t fshelp_return_malloced_buffer (@w{char *@var{buf}}, @w{size_t @var{len}}, @w{char **@var{rbuf}}, @w{mach_msg_type_number_t *@var{rlen}}) +Put data from the malloced buffer @var{buf}, @var{len} bytes long, into +@var{rbuf} (which is @var{rlen} bytes long), suitable for returning from +an RPC. If @var{len} is greater than zero, @var{buf} is freed, +regardless of whether an error is returned or not. +@end deftypefun + +@deftypefun error_t fshelp_set_options (@w{struct argp *@var{argp}}, @w{int @var{flags}}, @w{char *@var{argz}}, @w{size_t @var{argz_len}}, @w{void *@var{input}}) +Invoke @code{argp_parse} in the standard way, with data from @var{argz} +and @var{argz_len}. +@end deftypefun + +@deftypefun void fshelp_touch (@w{struct stat *@var{st}}, @w{unsigned @var{what}}, @w{volatile struct mapped_time_value *@var{maptime}}) +Change the stat times of @var{node} as indicated by @var{what} to +the current time. @var{what} is a bitmask of one or more of +the @code{TOUCH_ATIME}, @code{TOUCH_MTIME}, and @code{TOUCH_CTIME} +constants. +@end deftypefun + + +@emph{More to come!} @bye