     [file version.texi not included]

Copyright © 2002  Free Software Foundation, Inc.

Permission is granted to make and distribute verbatim copies of this manual provided the copyright notice and this permission notice are preserved on all copies.

Permission is granted to copy and distribute modified versions of this manual under the conditions for verbatim copying, provided also that the entire resulting derived work is distributed under the terms of a permission notice identical to this one.

Permission is granted to copy and distribute translations of this manual into another language, under the above conditions for modified versions.

The Hurd Server Interfaces
**************************

This file documents the GNU Hurd server's programmable interfaces. This edition of the documentation was last updated for version VERSION of the Hurd.

Introduction
************

The GNU Hurd is a user-extensible, multi-server operating system operating on top of a microkernel.  It is the GNU project's replacement for the Unix kernel.

The Hurd servers run in user space and cooperate in providing the features people usually expect from the Unix kernel.  This cooperation is done by sending messages to server provided objects.  The various types of objects implemented by the Hurd servers, the interfaces they provide, and how those interfaces are used in implementing the system are documented in this manual.

Audience
========

This manual is written for people who want to study, modify or extend the Hurd system.  It is mainly targeted at programmers, but also expert users who want to get a better understanding in how the system works might be able to take advantage of it.

Although this manual includes cross references into the user manual, it will not tell you how to take advantage of the Hurd system as a user.  In particular, it does not document the application programs that users can run at the command line to invoke Hurd specific features.

The manual is organized into two parts.  The first part documents the generic properties of the object and message system.  A good understanding of that is required if you want to use any of the Hurd interfaces.  The second part contains one chapter for each subsystem. One subsystem contains all the operations on one possible type of objects (but note that one object can actually be polymorph and implement several of the subsystems at once).

If you only are interested in a specific subsystem, you can start directly at that chapter after reading the first part of the manual. Some subsystems have features that rely on functionality implemented in other subsystems.  If that is the case, the text will say so.

GNU General Public License
==========================

     [file gpl.texinfo not included]

Object Management
*****************

The Hurd servers run as independent programs in user space.  To access them, messages are sent to the server using the microkernels inter-process communication (IPC) facility.  The details about IPC depend on the uncerlying microkernel, and are often very complex. However, the Hurd provides a convenience library that makes sending a message to a server and receiving the reply as easy as calling a function in the C programming language.  But although it looks like a function call, the function is actually executed in the remote server process.  This is called a remote procedure call (RPC).

The libhurduser library provides the client stub functions that take care of the details necessry to perform the IPC.  The prototypes for commonly used RPCs are available by including the <hurd.h> header file.  Inclusion of this header also requires defining _GNU_SOURCE.  Not so frequently used RPCs require inclusion of further header files.

     #define _GNU_SOURCE 1
     #include <hurd.h>
     #include <hurd/proc.h>

The Hurd servers don't implement any interfaces directly.  Instead, you always send the message to an object that is provided by the server.  One server usually provides many objects.  To sent a message to an object, you need a handle for that object, and the server must accept you as a valid holder for that handle.  The object handle is passed to the server as the first parameter of the RPC.

There are two ways you can get object handles.  Other programs can give you handles for objects to which they want to grant you access. Usually this is done by inheriting those handles from your parent process at the time your process is executed.  But you can also receive handles in messages that are sent to your process by some program at any later time.  The other way to get a valid object handle is as a return value of an RPC.  Some RPCs allow you to create new objects in the server, and in those cases the server will return a valid handle for that newly created object to you.

Any object usually implements many RPCs.  Which RPCs are supported depends on the type of the object.  The Hurd interfaces are grouped into several subsystems, and each subsystem contains RPCs that are closely related to each other.  Objects are not limited to implementing just the functions in one of the subsystems.  In fact, most if not all objects are polymorph and implement several related subsystems at the same time.

Although the server is required to implement all functions of a subsystem for an object that implements at least one of them, it is not guaranteed that every function in that subsystem does something useful for any given object.  Instead, calling an unsupported function on an object might just fail.

However, in general it is always allowed to at least make the attempt to use any RPC on any object at any time.  The servers have to take any precautions that are necessary to prevent malicious abuse, while the user has to expect weird behaviour, spurious failures and hard-to-detect bugs if he violates the protocol assumptions for server objects as documented in this manual.

Users don't get direct control over the server side objects, they only ever get access to them via the object handle they receive.  Some operations are implemented for every object in the Hurd, see XXX.

Memory Management
*****************

Document buffer exchange semantics.

Objects
*******

All objects provided by Hurd servers implement the functions in this subsystem, because they are implemented by the Hurd's object management library that is used by all Hurd servers.

 -- Function: error_t object_mod_refs (object_handle_t *OBJECT, int count)
     If count is positive, this function acquires COUNT references for the handle OBJECT for the object.

     If count is negative, this function deallocates -COUNT references for the handle OBJECT for the object.  If that number is greater than the current number of references, the handle becomes invalid and can not be used by this user to access the object anymore. If this was the last user of this object, the object will be destroyed and all resources to it will be deallocated.

     Returns 0 on success, and EINVAL if OBJECT is not a valid object handle for this user.

 -- Function: error_t object_release (object_handle_t *OBJECT)
     This function releases one reference for the handle OBJECT for the object.  If that was the last reference for this user, the handle becomes invalid and can not be used by this user to access the object anymore.  If this was the last user of this object, the object will be destroyed and all resources to it will be deallocated.

     Returns 0 on success, and EINVAL if OBJECT is not a valid object handle for this user.

XXX XXX XXX

Authentication
**************

The authentication subsystem provides an interface for trusted third parties (authentication servers) to establish a trusted channel of communication between a server and a user without requiring mutual trust between them.

After the trusted channel is established, the user receives an object handle from the server, and the server learns about the user's identity from the authentication server.

The prototypes for the functions in the authentication subsystem are available in the header file <hurd/auth.h>, but this file is also included indirectly by <hurd.h>.

Authentication Objects
======================

The identity of a user is defined by four ID vectors, each ID is represented by a number.  Any vector can be empty.  A zero among the IDs represents the superuser.  The four ID vectors that are associated with an authentication object are:

  * The effective user IDs

  * The effective group IDs

  * The available user IDs

  * The available group IDs

The effective IDs should be used by the server that provides the object handle to the user to check for the authorization of an operation that the user tries to perform on the object it receives. The available IDs should not be used in any way, they are reserved by the user for later use.  A user can turn available IDs into the corresponding effective IDs at a later time.

As a consequence of this policy, any user that holds a valid handle for a certain authentication object can use that to authorize operations on server provided objects with the user and group IDs associated with that authentication object, as long as the server trusts the authentication server.  Usually, all system Hurd servers will use the same global authentication server for all their authentications.

In the POSIX.1 personality of the Hurd, the first effective user ID is the POSIX user ID, while the first available user ID is the POSIX real user ID and the second available user ID is the POSIX saved user ID. The corresponding rules hold for the group IDs (just replace ``user'' with ``group'' in the previous sentence).

 -- Data type: auth_t
     The data type auth_t is the same as object_handle_t, but is used to emphasize that the object with this handle implements the authentication subsystem.

Getting Information about Auth Objects
======================================

 -- Function: error_t auth_getids (auth_t AUTH, idarray_t *EUIDS, int *EUIDS_LEN, idarray_t *AUIDS, int *AUIDS_COUNT, idarray_t *EGIDS, int *EGIDS_LEN, idarray_t *AGIDS, int *AGIDS_LEN)
     This function returns the ID vectors associated with the authentication handle AUTH.  The effective user IDs are returned in <*EUIDS, *EUIDS_LEN>, the available user IDs in <*AUIDS, *AUIDS_LEN>, the effective group IDs in <*EGIDS, *EGIDS_LEN>, and the available group IDs in <*AGIDS, *AGIDS_LEN>.

     Returns 0 on success, and EINVAL if AUTH is not a valid authentication handle for this user.

Creating new Auth Objects
=========================

 -- Function: error_t auth_makeauth (auth_t AUTH, autharray_t *OTHER_HANDLES, autharray_poly_t *OTHER_HANDLES_POLY, idarray_t EUIDS, int EUIDS_LEN, idarray_t AUIDS, int AUIDS_COUNT, idarray_t EGIDS, int EGIDS_LEN, idarray_t AGIDS, int AGIDS_LEN, auth_t *NEW_AUTH)
     This function creates a new authentication object and returns a handle for it in NEW_AUTH.  The handle will have one reference to the object.  The effective user IDs associated with the object will be <EUIDS, EUIDS_LEN>, the available user IDs will be <AUIDS, AUIDS_LEN>, the effective group IDs will be <EGIDS, EGIDS_LEN>, and the available group IDs will be <AGIDS, AGIDS_LEN>.

     If 0 is among any of the effective user IDs associated with AUTH or any of the OTHER_HANDLES, then there is no restriction on the IDs requested.  Otherwise, the following restrictions apply:

       * The union of the requested effective user IDs in EUIDS and available user IDs in AUIDS must be a subset of the union of the effective and available user IDs associated with AUTH and the OTHER_HANDLES.

       * The union of the requested effective group IDs in EGIDS and available group IDs in AGIDS must be a subset of the union of the effective and available group IDs associated with AUTH and the OTHER_HANDLES.

     The net effect is that the superuser can create authentication objects with arbitrary IDs, while unprivileged users are limited to merge and restrict operations.

     The function returns 0 on success, and EPERM if the requested IDs are not allowed given the provided authentication objects.

User Authentification
=====================

 -- Function: error_t auth_user_authenticate (auth_t AUTH, object_handle_t RENDEZVOUS, object_handle_poly_t RENDEZVOUS_POLY, object_handle_t *NEW_OBJECT)
     This function performs the user side of a reauthentication process that is used to establish a trusted connection between the user and a server.

     First, the user has to give the server it wants to authenticate with the RENDEZVOUS handle (ie it has to call io_reauthenticate with that handle).  Then it should follow up with this RPC on the authentication object it wants to use for the authentication process. The user must use the authentication server trusted by the server, or this RPC will just block until the rendesvouz object is destroyed.

     The function returns 0 on success.

 -- Function: error_t auth_server_authenticate (auth_t AUTH, object_handle_t RENDEZVOUS, object_handle_poly_t RENDEZVOUS_POLY, object_handle_t NEW_OBJECT, object_handle_poly_t NEW_OBJECT_POLY, idarray_t *EUIDS, int *EUIDS_LEN, idarray_t *AUIDS, int *AUIDS_COUNT, idarray_t *EGIDS, int *EGIDS_LEN, idarray_t *AGIDS, int *AGIDS_LEN)
     This function performs the server side of a reauthentication process that is used to establish a trusted connection between the user and a server.

     If the server returns success after receiving the user's rendesvouz object handle in an io_reauthenticate call, it should also perform with this RPC on an authentication object in the auth server it wants the user to use for this handshake.  The user must use the authentication server trusted by the server, or this RPC will just block until the rendesvouz object is destroyed.

     The function returns 0 on success.

Authentication Protocol
=======================

The complete handshake protocol to establish a trusted connection is as follows:

  * The user creates a rendezvous object.  The rendezvous object is used to match up the user and the server request in the authentication server.  Because the handshake must be completed before the rendezvous object is destroyed, this object also provides an upper limit to how long a handshake can take.

  * The user requests a reauthentication for a given object by sending the io_reauthenticate message to that object, passing a rendezvous object handle to the server.

  * The server calls auth_server_authenticate on an object in an auth server it trusts to know the correct user and group IDs of the user (usually the system's default auth server).  It passes on the rendezvous object handle it received from the client, and the server port the ciet should receive.  The server returns success to the user's io_reauthenticate call.

  * The user follows up with an auth_user_authenticate on the auth object which IDs it wants the server to know about.  It also passes a handle to the rendesvouz object.

  * The authentication server can now match up the server and the user request using the rendesvouz object handles.  It gives the user the server object handle, and the server the IDs of the authentication object the user used.  The server can now use those for authentification purposes.

Filesystem Control
******************

Filesystems play an important role in the Hurd.  While the authentication interface allows to establish trusted communication channels between users and servers, the filesystem allows to access the Hurd servers and integrate other servers into the system.

Traditionally, an IPC system has a central name server which is used to look up the initial (root) object to a server by its name.  This root object is then used to send messages to the server, probably requesting further objects provided by this server.

The Hurd does not use a central name server to make root objects to the other servers in the system accessible to the user.  Instead, for most purposes, the filesystem is used directly.  Conversely, the filesystem is implemented by Hurd servers and the objects they provide.  These objects typically implement the file and directory interfaces, but to allow to modify the file system, further objects and interfaces are provided.

One filesystem is the root filesystem for a program, and an object handle that represents the root directory is inherited by a process from its parent process.  The same is true for the object representing the current working directory.

Filesystems that are mounted into the root filesystems are accessed indirectly via the root filesystem (see pathname resolution).  Every filesystem knows about the filesystems that are directly mounted to nodes they provide, but not about filesystems which are mounted to nodes provided by the mounted filesystem.  This means that the filesystems visible to a program, starting from the root object, are organized in a hierarchical tree.

Every filesystem provides a filesystem control object, which can be used to modify the filesystem's parameters at runtime and how it is connected (``mounted'') to a node in its parent filesystem.

 -- Data type: fsys_t
     The data type fsys_t is the same as object_handle_t, but is used to emphasize that the object with this handle implements the filesystem control subsystem.

Filesystem Startup
==================

When a filesystem server is started up to be attached to a node provided by an existing filesystem server, it has a special object handle inserted into it, the bootstrap object handle.  The bootstrap object is technically a filesystem object, but it only implements a single interface, fsys_startup.  The filesystem that starts up is expected to send the fsys_startup message to the bootstrap object to complete the process of mounting itself into the parent filesystem.

 -- Function: error_t fsys_startup (object_handle_t BOOTSTRAP, int OPEN_FLAGS, fsys_t FSYS, object_handle_poly_t FSYS_POLY, object_handle_t *UNDERLYING_NODE)
     This function notifies the parent filesystem, which provides the object with the handle BOOTSTRAP, that this filesystem is ready to process requests, and thus completes the process of mounting the filesystem to a node provided by the parent filesystem.

     A handle to this filesystems control object should be passed in FSYS, so that the parent filesystem can retrieve the root directory object and perform other requested operations later on.

     OPEN_FLAGS are used as flags to open the underlying node to which the filesystem is attached.  A handle to the object providing this node is returned in UNDERLYING_NODE.  Which use the translator makes of this node is left to the implementation.  Some single-node filesystems (like null) use it to inherit certain file attributes such as owner, group, and access modes.  Other filesystems might use it to store precious information that should be preserved for the next time the filesystem is started up.

     The function returns 0 on success.

Sometimes your filesystem doesn't really want to act as a filesystem itself at all, but just delegate the service to some other filesystem server.

 -- Function: error_t fsys_forward (fsys_t FSYS, object_handle_t REQUESTOR, object_handle_poly_t REQUESTOR_POLY, data_t COMMAND, int COMMAND_LEN)
     This function tries to delegate the filesystem services we are expected to provide to FSYS.  REQUESTOR is our bootstrap object handle.  Eventually, FSYS or another delegate should follow up with a FSYS_STARTUP call on REQUESTOR.

     The command line in <COMMAND, COMMAND_LEN, which must be provided in argz format, describes closer the filesystem service we expect from FSYS.

     The function returns 0 on success.

Terminating Filesystems
=======================

 -- Function: error_t fsys_goaway (fsys_t FSYS, int FLAGS)
     This function requests that the filesystem FSYS shuts down and terminates.  FLAGS controls how hard the filesystem should try to go away and is a bitwise-OR of the following values:

       FSYS_GOAWAY_NOWAIT Do not wait for the shut down to complete and return immediately.  The default is to wait until the filesystem is completely shut down.

       FSYS_GOAWAY_NOSYNC Do not write back the modifications to the physical media before shutting down.

       FSYS_GOAWAY_FORCE Shut down the filesystem even if there are currently users accessing it.

       FSYS_GOAWAY_UNLINK Shut down the filesystem only if it provides a single node rather than a whole directory hierarchy.

       FSYS_GOAWAY_RECURSE Shut down child filesystems recursively.

     The function returns 0 on success.

Accessing Nodes on Filesystems
==============================

In general, nodes are accessed by using the dir_lookup RPC on an existing directory object.  The initial root directory object can not be retrieved this way, but has to be requested with the fsys_getroot RPC.

 -- Function: error_t fsys_getroot (fsys_t FSYS, object_handle_t DOTDOT_NODE, idarray_t *GEN_UIDS, int GEN_UIDS_LEN, idarray_t *GEN_GIDS, int GEN_GIDS_LEN, int OPEN_FLAGS, retry_type DO_RETRY, string_t RETRY_NAME, object_handle_t FILE)
     This function requests a root directory object for the filesystem FSYS, authenticated with the user IDs <GEN_UIDS, GEN_UIDS_LEN> and the group IDs <GEN_GIDS, GEN_GIDS_LEN>.  A handle for an unauthenticated object to the parent directory (the directory this filesystem's root node is contained in) should be provided in DOTDOT_NODE for later use.

     The meaning of OPEN_FLAGS, the details of the lookup procedure, and the possible return values for DO_RETRY, RETRY_NAME and FILE are documented in dir_lookup.

     The function returns 0 on success.

Filesystem Synchronization
==========================

 -- Function: error_t fsys_syncfs (fsys_t FSYS, int WAIT, int DO_CHILDREN)
     This function requests to flush all modifications in the filesystem to the physical media.  If WAIT is true, the function does not return until the synchronization has been completed.  If DO_CHILDREN is true, all hild filesystems are also synchronised recursively.

     The function returns 0 on success.

Filesystem Runtime Options
==========================

Many filesystems have command line options, and most of them support changing those command line options at runtime, without restarting the filesystem.

 -- Function: error_t fsys_get_options (fsys_t FSYS, data_t *OPTIONS, int *OPTIONS_LEN)
     This function retrieves the currently active command line options and returns them in <OPTIONS, OPTIONS_LEN> in argz format (NUL separated strings).  Default options are not shown.

     The function returns 0 on success.

 -- Function: error_t fsys_set_options (fsys_t FSYS, data_t OPTIONS, int OPTIONS_LEN, int DO_CHILDREN)
     This function tries to set the command line options for the filesystem FSYS to <OPTIONS, OPTIONS_LEN> which is in argz format (NUL separated strings).  Options not contained in <OPTIONS, OPTIONS_LEN> are not changed.

     If DO_CHILDREN is true, an attempt is made to set the same options in all child filesystems recursively.

     The function returns 0 on success.

 -- Function: error_t fsys_getfile (fsys_t FSYS, idarray_t GEN_UIDS, int GEN_UIDS_LEN, idarray_t GEN_GIDS, int GEN_GIDS_LEN, data_t FILEHANDLE, int FILEHANDLE_LEN, object_handle_t *FILE)
     FIXME: Add desc.

 -- Function: error_t fsys_getpriv (fsys_t FSYS, object_handle_t *HOST_PRIV, object_handle_t *DEVICE_MASTER, object_handle_t *FSTASK)
     FIXME: Add desc.

 -- Function: error_t fsys_init (fsys_t FSYS, object_handle_t PROC_SERVER, object_handle_poly_t PROC_SERVER_POLY, auth_t AUTH_HANDLE)
     FIXME: Add desc.

Files and Directories
*********************

The filesystem interface defines how to operate on files, directories and other filesystem nodes.

Files
=====

File objects are returned by a successful dir_lookup call.  They implement the file interface described in this section and the I/O interface.  Some files also implement the directory interface (such files are usually called directories).

Everytime a file is looked up, a new object is created and a handle for it is returned.  The GNU C library implements open() by looking up the file with the given name and then adding a file descriptor to the descriptor table referring to the file object returned.  Other functions that operate on file descriptors are then often implemented by RPCs to the underlying file objects.

File Attributes
---------------

The current attributes of a file can be retrieved with the io_stat RPC, which is part of the more generic I/O interface.  Some of the attributes can be modified directly with the interfaces described in this subsection.

 -- Function: error_t file_chown (file_t FILE, uid_t UID, gid_t GID)
     This function sets the owner and/or the group of the file FILE.

     If UID is not -1, the owner of the file is set to UID.

     If GID is not -1, the group of the file is set to GID.

     The function returns 0 if successful.

 -- Function: error_t file_chauthor (file_t FILE, uid_t AUTHOR)
     This function sets the author of the file FILE to UID.

     The function returns 0 if successful.

 -- Function: error_t file_chmod (file_t FILE, mode_t MODE)
     This function sets the mode bits of the file FILE to MODE.

     The mode bits include the read/write/executable bits for the owner, the group, the other users and the user without any user IDs, as well as some other bits.

     The function returns 0 if successful.

 -- Function: error_t file_chflags (file_t FILE, int FLAGS)
     This function sets the flags of the file FILE to FLAGS.

     The meaning of the flags are user defined.  The flags are not interpreted by the standard Hurd servers in any way.  The lower 16 bits can be set by the owner of the file, the upper 16 bits are reserved to the superuser.

     The function returns 0 if successful.

 -- Function: error_t file_utimes (file_t FILE, time_value_t NEW_ATIME, time_value_t NEW_MTIME)
     This function sets the access and modification time of the file FILE to NEW_ATIME resp. NEW_MTIME.

     If the microseconds in either time are -1 (all bits on), the remainder of the time value is ignored and the corresponding time is set to the current time.

     The function returns 0 if successful.

 -- Function: error_t file_set_time (file_t FILE, loff_t NEW_SIZE)
     This function sets the size of the file FILE to NEW_SIZE.

     If NEW_SIZE is smaller than the current size, the file is truncated.  If NEW_SIZE is larger than the current size, the new area is zero filled.

     The function returns 0 if successful.

File Access Rights
------------------

 -- Function: error_t file_check_access (file_t FILE, int *ALLOWED)
     This function checks which access rights exist on the file FILE for the user, regardless of the current open modes for FILE. *ALLOWED will contain a bitwise OR of O_READ, O_WRITE and O_EXEC.

     The access modes are not necessarily the same as an open or exec would allow: O_EXEC is set for root even if no executable bits are on (in which case file_exec should fail) and O_WRITE is set a directory can be modified, even though it can't be written directly.

     The function returns 0 if successful.

Executing a File
----------------

For normal programs, it is sufficient to be able to read it if you want to start them as an executable.  This is because you can always set up your own process image with the program you read.  This is equivalent to copying the program to your home directory, activating the executable bit for the copy of the file, and run the program from there.  However, this will not work for programs which require the set user ID or set group ID flag.

Executing a program file is a function of the filesystem because the filesystem server will usually have broader privileges than individual users of the filesystem, that can be used to launch applications that have the set user ID or set group ID flag turned on.  In this case the filesystem will take appropriate precautions to not leak any privileges to the user.

 -- Function: error_t file_exec (file_t FILE, task_t TASK, int FLAGS, data_t ARGV, int ARGV_LEN, data_t ENVP, int ENVP_LEN, object_handle_t *FDARRAY, object_handle_poly_t FDARRAY_POLY, int FDARRAY_LEN, object_handle_t *OBJECTARRAY, object_handle_poly_t OBJECTARRAY_POLY, int OBJECTARRAY_LEN, int *INTARRAY, int INTARRAY_LEN, object_handle_t *DEALLOC_HANDLES, int DEALLOC_HANDLES_LEN, object_handle_t *DESTROY_HANDLES, int DESTROY_HANDLES_LEN)
     This function overlays the task TASK with the file FILE. Necessary initialization, including authentication changes associated with setuid/setgid execution is handled by the filesystem.  For the exact meaning of all the arguments, see exec_exec in the exec server interface.

     Note that this provides access to all objects that are passed in the message.  This usually also includes your handle to the authentication object.  This is unavoidable if you want to run setuid/setgid applications from a filesystem not owned by you, but it might be undesirable if the filesystem is provided by an untrusted user.  The moral of the story is that you should not run programs from untrusted filesystems directly, or, if you have to, first drop all user and group IDs in your authentication object (running the program without user or group IDs).

     The function returns 0 if successful.

File Locking
------------

The file locking interface in the Hurd provides only a very simple advisory file lock for the whole file.  Full POSIX record file locking is not yet supported.

 -- Function: error_t file_lock (file_t FILE, int FLAGS)
     This function manipulates the lock for the file FILE according to the value of FLAGS, which can be one of the following (as defined in <sys/file.h>:

       LOCK_EX Acquire an exclusive lock.

       LOCK_SH Acquire a shared lock.

       LOCK_UN Release a previously acquired lock.

     Optionally, the value of LOCK_NB can be OR'ed into FLAGS to prevent blocking while waiting for a lock to become available.

     The function returns 0 if successful.

 -- Function: error_t file_lock_stat (file_t FILE, int *MY_STATUS, int *STATUS)
     This function retrieves the current status of the file FILE with regards to locks.

     If MY_STATUS is LOCK_EX or LOCK_SH, then the caller holds the corresponding lock and STATUS will follow the value of MY_STATUS.

     If MY_SYTATUS is LOCK_UN, the caller does not have a lock on FILE.  In this case, if STATUS is LOCK_EX or LOCK_SH, somebody else holds the corresponding lock, but if STATUS is LOCK_UN, then the file is currently not locked by anybody.

     The function returns 0 if successful.

File Change Notifications
-------------------------

You can request notifications from the server whenever a file changes.

 -- Function: error_t file_notice_changes (file_t FILE, object_handle_t NOTIFY, object_handle_poly_t NOTIFY_POLY)
     This function requests that the server sends file_changed notification messages to NOTIFY whenever the file FILE changes.

     One notification message is sent immediately before the function returns, to synchronize the caller and verify that NOTIFY is a valid object to which notification messages can be sent.  Further messages are sent whenever there is something interesting happening on FILE.

     The function returns 0 if successful.

File Synchronization
--------------------

 -- Function: error_t file_sync (file_t FILE, int WAIT, int OMIT_METADATA)
     This function requests that all changes to the file FILE are written back to the physical media.  If WAIT is true, this call does return after the synchronization has been completed.

     If OMIT_METADATA is true, the filesystem is allowed to only flush the content of the file, and not to flush the metadata.

     The function returns 0 if successful.

 -- Function: error_t file_getfh (file_t FILE, data_t *FILEHANDLE, int *FILEHANDLE_LEN)
     FIXME: Add desc.

 -- Function: error_t file_getlinknode (file_t FILE, object_handle_t *LINKNODE)
     FIXME: Add desc.

 -- Function: error_t file_get_storage_info (file_t FILE, portarray_t *PORTS, int *PORTS_LEN, intarray_t *INTS, int *INTS_LEN, off_array_t *OFFSETS, int *OFFSETS_LEN, data_t *DATA, int *DATA_LEN)
     FIXME: Add desc.

File to Filesystem
------------------

 -- Function: error_t file_getcontrol (file_t FILE, fsys_t *FSYS)
     This function returns a handle for the control object of the filesystem providing the file FILE.  This is a privileged operation, which is only available to the owner of the filesytem.

     The function returns 0 if successful.

Filesystem Operations
---------------------

The interfaces in this subsection do not operate on the file object they are sent to, but on the filesystem that provides the file.  They are provided by the file interface because they only require the access right to a file object rather than the whole filesystem (only the controller of a filesystem is allowed to retrieve a filesystem control object handle).

 -- Function: error_t file_statfs (file_t FILE, fsys_statfsbuf_t INFO)
     This function returns information about the filesystem that provides the file FILE in *INFO.

     The function returns 0 on success.

 -- Function: error_t file_syncfs (file_t FILE, int WAIT, int DO_CHILDREN)
     This function is equivalent to calling fsys_syncfs on the control object for the filesystem that provides FILE.

 -- Function: error_t file_get_fs_options (file_t FILE, data_t *OPTIONS, int *OPTIONS_LEN)
     This function is equivalent to calling fsys_get_options on the control object for the filesystem that provides FILE.

 -- Function: error_t file_set_translator (file_t FILE, int PASSIVE_FLAGS, int ACTIVE_FLAGS, int OLDTRANS_FLAGS, data_t PASSIVE, int PASSIVE_LEN, object_handle_t ACTIVE)
     FIXME: Add desc.

 -- Function: error_t file_get_translator (file_t FILE, data_t *TRANSLATOR, int *TRANSLATOR_LEN)
     FIXME: Add desc.

 -- Function: error_t file_get_translator_cntl (file_t FILE, mach_port_t *TRANSLATOR_CNTL)
     FIXME: Add desc.

 -- Function: error_t file_reparent (file_t FILE, object_handle_t PARENT, object_handle_t *NEW_FILE)
     FIXME: Add desc.

Directories
===========

Some file objects also implement the directory related interfaces. Such files are usually considered to be directories.  However, there is nothing that enforces a distinction between a directory and a file. In fact, every directory is usually and usefully also a file. Historically, the content of a directory file is the content of the directory listing in a file system specific binary format.  In the Hurd, there is no requirement for this.  The content of a directory file could also be the directory content in a compressed archive format, for example.

In the Hurd, the canonical way to test if an object is a directory object is to call dir_lookup with the filename ``.''.  If this succeeds, then the convention is to assume that the object is providing standard directory operations and should be considered to be a directory by POSIX applications accessing it through file descriptors etc.

Directory Lookup
----------------

 -- Function: error_t dir_lookup (file_t START_DIR, string_t FILE_NAME, int FLAGS, mode_t MODE, retry_type *DO_RETRY, string_t *RETRY_NAME, object_handle_t *RESULT)
     This function is used to make an attempt to lookup (open) the file FILE_NAME, with flags FLAGS and open mode MODE in directory START_DIR.  FILE is not limited to file entries in the directory START_DIR, but usually will be a full absolute or relative filename (ie it can contain slashes, ``..'' etc).  It provides the core functionality for the Hurd's virtual file system layer, which is implemented in the client (usually the C library). Because the Hurd system is split up into many servers, and a lot of functionality is also implemented in the client side, this function can not do all the work for the client, and has quite complex semantics.  See XXX(pathname resolution) for more information how this function is used in the Hurd.

     The following results are possible:

       * If RETRY_TYPE is FS_RETRY_NORMAL and RETRY_NAME is the empty string, then the lookup succeeded and RESULT holds the desired (file) object handle.  This is the simplest case.

       * If RETRY_TYPE is FS_RETRY_NORMAL and RETRY_NAME is a string with a non-zero length, then the lookup could not be completed because at least a part of the file name is not resolved by the server that provides START_DIR, but by some other server, and thus the user has to retry.  The server provides the part that could not be succesfully looked up in RETRY_NAME and the root directory object on which the user should attempt the lookup of the remaining part in RESULT.

       * If RETRY_TYPE is FS_RETRY_REAUTH, then RESULT and RETRY_NAME have the same meaning as for FS_RETRY_NORMAL, but the user should reauthenticate RESULT before using it.  This is usually required whenever the user is crossing filesystem boundaries in the path.

          It is also recommended that the user always performs a lookup on the reauthenticated object, even if the retry_name is the empty string. This allows the filesystem to urther delegate accesses to its root node.

       * If RETRY_TYPE is FS_RETRY_MAGICAL, then the server can not complete the lookup, but also does not know about any other server which could.  In this case it asks the user to take over the initiative again, providing more information about which magic should be applied in RETRY_NAME:

            * If RETRY_NAME starts with a `/', the filesystems wants the user to look up the file RETRY_NAME starting from its root directory object.

            * If RETRY_NAME starts with ``fd/'', followed by a number, the filesystems wants the user to open its own file descriptor with that number.  This is used by the magic translator on ``/dev/fd''.  Note that ``/dev/stdin'' is a symlink to ``/dev/fd/0'', and ``/dev/stdout'', ``/dev/stderr'' are symlinks to ``/dev/fd/1'', ``/dev/fd2''.

            * If RETRY_NAME is ``tty'', the filesystem wants the user to look up its controlling terminal.  If RETRY_NAME is ``tty/'' followed by a filename, the user should treat the controlling terminal as a directory object and continue to look up the following filename in that directory.

     All I/O objects, not only directories, should support dir_lookup with the empty lookup name ``'', and ``reopen'' the object in this case.  Reopening means to create a new, second object that represents the same underlying entity (file, socket, ...).

     The function returns 0 if successful.

Directory Listing
-----------------

 -- Function: error_t dir_readdir (file_t DIR, data_t *DATA, int *DATA_LEN, int START_ENTRY, int ENTRIES, size_t MAX_SIZE, int *AMOUNT)
     This function is used to read out the content of a directory.  Each entry in the directory listing is identified by an index number starting at 0 and running through the file.  The first entry to be read is provided in START_ENTRY, the total number of entries returned is ENTRIES (or any convenient number if ENTRIES is -1).

     For each entry, a struct directs is returned in <*DATA, *DATA_LEN>.  The number of entries successfully read is returned in *AMOUNT.

     If MAX_SIZE is not zero, it specifies the maximum size of the returned buffer in bytes.

     The function returns 0 if successful.

Directory Manipulation
----------------------

 -- Function: error_t dir_mkdir (file_t DIRECTORY, string_t NAME, mode_t MODE)
     This function creates a new directory with the name NAME in the directory DIRECTORY.  The directory will have the mode MODE.

     The function returns 0 if successful.

 -- Function: error_t dir_rmdir (file_t DIRECTORY, string_t NAME)
     This function deletes the directory NAME in the directory DIRECTORY.  The directory NAME must be empty for this call to succeed.

     The function returns 0 if successful.

 -- Function: error_t dir_unlink (file_t DIRECTORY, string_t NAME)
     This function removes the directory entry for the file with the name NAME in the directory DIRECTORY.  If this was the last directory entry for this file, and there are no active users of the file, it is deleted permanently.

     The function returns 0 if successful.

 -- Function: error_t dir_link (file_t DIR, file_t FILE, string_t NAME, int EXCL)
     This function creates a new directory entry for the file FILE in the directory DIR, under the name NAME.  If EXCL is true, only create the directory entry if an entry with that name doesn't exist already.

     The function returns 0 if successful, and EXDEV if FILE and DIRECTORY are not implemented by the same filesystem.

 -- Function: error_t dir_rename (file_t OLDDIRECTORY, string_t OLDNAME, file_t NEWDIRECTORY, string_t NEWNAME, int EXCL)
     This functions renames the directory entry OLDNAME in the directory OLDDIRECTORY to the directory entry NEWNAME in the directory NEWDIRECTORY.  If NEWDIRECTORY is different from OLDDIRECTORY, the file is moved.

     The function returns 0 if successful, and EXDEV if OLDDIRECTORY and NEWDIRECTORY are not implemented by the same filesystem.

If two filesystems can cooperate via protocols to allow users to hard link or rename across their filesystem border, then they can implement the above interfaces and don't need to return EXDEV.  However, in this case they are expected to follow the POSIX semantics for these operations.

 -- Function: error_t dir_mkfile (file_t DIRECTORY, int FLAGS, mode_t MODE, object_handle_t *NEWNODE)
     FIXME: Add desc.  This function creates a new file in the directory DIRECTORY, with the given FLAGS and MODE, and returns a handle for the file object in NEWNODE.  However, the file is never actually entered into the directory under any name. This is very useful to create temporary files, for example.

     The directory DIRECTORY is only used to validate the access.  To permanently enter the file into the filesystem, dir_link can be used.

     The function returns 0 if successful.

Directory Change Notifications
------------------------------

You can request notifications from the server whenever a directory changes.

 -- Function: error_t dir_notice_changes (file_t DIR, object_handle_t NOTIFY, object_handle_poly_t NOTIFY_POLY)
     This function requests that the server sends dir_changed notification messages to NOTIFY whenever the directory DIRECTORY changes.

     One notification message is sent immediately before the function returns, to synchronize the caller and verify that NOTIFY is a valid object to which notification messages can be sent.  Further messages are sent whenever there is something interesting happening on DIRECTORY.

     The function returns 0 if successful.

Input and Output
****************

 -- Function: error_t io_write (io_t IO_OBJECT, data_t DATA, int DATA_LEN, loff_t OFFSET, vm_size_t *AMOUNT)
     FIXME: Add desc.

 -- Function: error_t io_read (io_t IO_OBJECT, data_t *DATA, int *DATA_LEN, loff_t OFFSET, vm_size_t AMOUNT)
     FIXME: Add desc.

 -- Function: error_t io_seek (io_t IO_OBJECT, loff_t OFFSET, int WHENCE, loff_t *NEWP)
     FIXME: Add desc.

 -- Function: error_t io_readable (io_t IO_OBJECT, vm_size_t *AMOUNT)
     FIXME: Add desc.

 -- Function: error_t io_set_all_openmodes (io_t IO_OBJECT, int NEWBITS)
     FIXME: Add desc.

 -- Function: error_t io_get_openmodes (io_t IO_OBJECT, int *BITS)
     FIXME: Add desc.

 -- Function: error_t io_set_some_openmodes (io_t IO_OBJECT, int BITS_TO_SET)
     FIXME: Add desc.

 -- Function: error_t io_clear_some_openmodes (io_t IO_OBJECT, int BITS_TO_CLEAR)
     FIXME: Add desc.

 -- Function: error_t io_async (io_t IO_OBJECT, object_handle_t NOTIFY_PORT, object_handle_poly_t NOTIFY_PORT_POLY, object_handle_t *ASYNC_ID_PORT)
     FIXME: Add desc.

 -- Function: error_t io_mod_owner (io_t IO_OBJECT, pid_t OWNER)
     FIXME: Add desc.

 -- Function: error_t io_get_owner (io_t IO_OBJECT, pid_t *OWNER)
     FIXME: Add desc.

 -- Function: error_t io_get_icky_async_id (io_t IO_OBJECT, object_handle_t *ICKY_ASYNC_ID_PORT)
     FIXME: Add desc.

 -- Function: error_t io_select (io_t IO_OBJECT, object_handle_t REPLY, natural_t TIMEOUT, int *SELECT_TYPE)
     FIXME: Add desc.

 -- Function: error_t io_stat (io_t STAT_OBJECT, io_statbuf_t *STAT_INFO)
     FIXME: Add desc.

 -- Function: error_t io_reauthenticate (io_t AUTH_OBJECT, object_handle_t RENDEZVOUS2, object_handle_poly_t RENDEZVOUS2_POLY)
     FIXME: Add desc.

 -- Function: error_t io_restrict_auth (io_t IO_OBJECT, object_handle_t *NEW_OBJECT, idarray_t UIDS, int UIDS_LEN, idarray_t gIDS, int GIDS_LEN)
     FIXME: Add desc.

 -- Function: error_t io_duplicate (io_t IO_OBJECT, object_handle_t *NEWPORT)
     FIXME: Add desc.

 -- Function: error_t io_server_version (io_t VERS_OBJECT, string_t SERVER_NAME, int *SERVER_MAJOR_VERSION, int *SERVER_MINOR_VERSION, int *SERVER_EDIT_LEVEL)
     FIXME: Add desc.

 -- Function: error_t io_map (io_t IO_OBJECT, object_handle_t *MEMOBJRD, object_handle_t *MEMOBJWT)
     FIXME: Add desc.

 -- Function: error_t io_map_cntl (io_t IO_OBJECT, object_handle_t *MEMOBJ)
     FIXME: Add desc.

 -- Function: error_t io_get_conch (io_t IO_OBJECT)
     FIXME: Add desc.

 -- Function: error_t io_release_conch (io_t IO_OBJECT)
     FIXME: Add desc.

 -- Function: error_t io_eofnotify (io_t IO_OBJECT)
     FIXME: Add desc.

 -- Function: error_t io_prenotify (io_t IO_OBJECT, vm_offset_t WRITE_START, vm_offset_t WRITE_END)
     FIXME: Add desc.

 -- Function: error_t io_postnotify (io_t IO_OBJECT, vm_offset_t WRITE_START, vm_offset_t WRITE_END)
     FIXME: Add desc.

 -- Function: error_t io_readnotify (io_t IO_OBJECT)
     FIXME: Add desc.

 -- Function: error_t io_readsleep (io_t IO_OBJECT)
     FIXME: Add desc.

 -- Function: error_t io_sigio (io_t IO_OBJECT)
     FIXME: Add desc.

 -- Function: error_t io_pathconf (io_t IO_OBJECT, int NAME, int *VALUE)
     FIXME: Add desc.

 -- Function: error_t io_identity (io_t IO_OBJECT, object_handle_t *IDPORT, object_handle_t *FSIDPORT, ino64_t *FILENO)
     FIXME: Add desc.

 -- Function: error_t io_revoke (io_t IO_OBJECT)
     FIXME: Add desc.

Sockets
*******

 -- Function: error_t ifsock_getsockaddr (file_t FILE, object_handle_t *SOCKADDR)
     FIXME: Add desc.

Execution
*********

 -- Function: error_t exec_exec (file_t EXECSERVER, object_handle_t FILE, object_handle_polyt FILE_POLY, object_handle_t OLDTASK, int FLAGS, data_t ARGV, int ARGV_LEN, data_t ENVP, int ENVP_LEN, portarray_t DTABLE, object_handle_poly_t DTABLE_POLY, int DTABLE_LEN, portarray_t PORTARRAY, object_handle_poly_t PORTARRAY_POLY, int PORTARRAY_LEN, intarray_t iNTARRAY, int INTARRAY_LEN, object_handle_poly_t DEALLOCNAMES, int DEALLOCNAMES_LEN, object_handle_poly_t DESTROYNAMES, int DESTROYNAMES_LEN)
     FIXME: Add desc.

 -- Function: error_t exec_init (file_t EXECSERVER, auth_t AUTH_HANDLE, object_handle_t PROC_SERVER, object_handle_poly_t PROC_SERVER_POLY)
     FIXME: Add desc.

 -- Function: error_t exec_setexecdata (file_t EXECSERVER, portarray_t PORTS, object_handle_poly_t PORTS_POLY, int PORTS_LEN, intarray_t INTS, int INTS_LEN)
     FIXME: Add desc.

Messages
********

 -- Function: error_t msg_sig_post (object_handle_t PROCESS, int SIGNAL, natural_t SIGCODE, object_handle_t REFPORT)
     FIXME: Add desc.

 -- Function: error_t msg_proc_newids (object_handle_t PROCESS, object_handle_t TASK, pid_t PPID, pid_t PGRP, int ORPHANED)
     FIXME: Add desc.

 -- Function: error_t msg_add_auth (object_handle_t PROCESS, auth_t AUTH)
     FIXME: Add desc.

 -- Function: error_t msg_del_auth (object_handle_t PROCESS, object_handle_t TASK, intarray_t UIDS, int UIDS_LEN, intarray_t GIDS, int GIDS_LEN)
     FIXME: Add desc.

 -- Function: error_t msg_get_init_port (object_handle_t PROCESS, object_handle_t REFPORT, int WHICH, object_handle_t *PORT)
     FIXME: Add desc.

 -- Function: error_t msg_set_init_port (object_handle_t PROCESS, object_handle_t REFPORT, int WHICH, object_handle_t PORT, object_handle_poly_t PORT_POLY)
     FIXME: Add desc.

 -- Function: error_t msg_get_init_ports (object_handle_t PROCESS, object_handle_t REFPORT, portarray_t *PORTS, int *PORTS_LEN)
     FIXME: Add desc.

 -- Function: error_t msg_set_init_ports (object_handle_t PROCESS, object_handle_t REFPORT, portarray_t PORTS, object_handle_poly_t PORTS_POLY, int PORTS_LEN)
     FIXME: Add desc.

 -- Function: error_t msg_get_init_int (object_handle_t PROCESS, object_handle_t REFPORT, int WHICH, int *VALUE)
     FIXME: Add desc.

 -- Function: error_t msg_set_init_int (object_handle_t PROCESS, object_handle_t REFPORT, int WHICH, int VALUE)
     FIXME: Add desc.

 -- Function: error_t msg_get_init_ints (object_handle_t PROCESS, object_handle_t REFPORT, intarray_t *VALUES, int *VALUES_LEN)
     FIXME: Add desc.

 -- Function: error_t msg_set_init_ints (object_handle_t PROCESS, object_handle_t REFPORT, intarray_t VALUES, int VALUES_LEN)
     FIXME: Add desc.

 -- Function: error_t msg_get_dtable (object_handle_t PROCESS, object_handle_t REFPORT, portarray_t *DTABLE, int *DTABLE_LEN)
     FIXME: Add desc.

 -- Function: error_t msg_set_dtable (object_handle_t PROCESS, object_handle_t REFPORT, portarray_t DTABLE, object_handle_poly_t DTABLE_POLY, int DTABLE_LEN)
     FIXME: Add desc.

 -- Function: error_t msg_get_fd (object_handle_t PROCESS, object_handle_t REFPORT, int FD, object_handle_t *PORT)
     FIXME: Add desc.

 -- Function: error_t msg_set_fd (object_handle_t PROCESS, object_handle_t REFPORT, int FD, object_handle_t PORT, object_handle_poly_t PORT_POLY)
     FIXME: Add desc.

 -- Function: error_t msg_get_environment (object_handle_t PROCESS, data_t *VALUE, int *VALUE_LEN)
     FIXME: Add desc.

 -- Function: error_t msg_set_environment (object_handle_t PROCESS, object_handle_t REFPORT, data_t VALUE, int VALUE_LEN)
     FIXME: Add desc.

 -- Function: error_t msg_get_env_variable (object_handle_t PROCESS, string_t VARIABLE, data_t *VALUE, int *VALUE_LEN)
     FIXME: Add desc.

 -- Function: error_t msg_set_env_variable (object_handle_t PROCESS, object_handle_t REFPORT, string_t VARIABLE, string_t VALUE, boolean_t REPLACE)
     FIXME: Add desc.

 -- Function: error_t msg_sig_post_untraced (object_handle_t PROCESS, int SIGNAL, natural_t SIGCODE, object_handle_t REFPORT)
     FIXME: Add desc.

 -- Function: error_t msg_report_wait (object_handle_t PROCESS, object_handle_t THREAD, string_t WAIT_DESC, mach_msg_id_t *WAIT_RPC)
     FIXME: Add desc.

 -- Function: error_t msg_describe_ports (object_handle_t PROCESS, object_handle_t REFPORT, object_handle_array_t NAMES, int NAMES_LEN, data_t *DESCRIPTIONS, int *DESCRIPTIONS_LEN)
     FIXME: Add desc.

Crash
*****

 -- Function: error_t crash_dump_task (object_handle_t CRASHSERVER, object_handle_t TASK, file_t FILE, int SIGNO, integer_t SIGCODE, int SIGERROR, natural_t EXC, natural_t CODE, natural_t SUBCODE, object_handle_t CTTYID_PORT, object_handle_poly_t CTTYID_PORT_POLY)
     FIXME: Add desc.

Interruption
************

 -- Function: error_t interrupt_operation (object_handle_t OBJECT, int TIMEOUT)
     This function requests that the currently pending operation on OBJECT is interrupted and returns immediately.  How this is implemented depends on the type of the object and the willingness of the server providing it.  The TIMEOUT argument specifies how long the caller should try to deliver the request.

     The function returns 0 if successful.

Glossary
********

Author

The author of a file is the user who created the file.  It is preserved when the file is copied.  It does not have any syntactical meaning in the Hurd (ie, it is not used for any permission checks etc).

Inter-Process Communication, IPC

A mechanism to communicate between independently running programs.  In the Hurd, the microkernel implements the IPC facility at the system level.  In Unix, usually high level abstractions like sockets are used.  The complexity of IPC mechanisms various enormously between the implementations.  It can be as simple as a socket or as complex as the Mach ports system.  Usually, messages are sent indirectly via remote procedure calls (RPC).

Remote Procedure Call, RPC

A remote procedure call is a function that is executed in a remote server program.  You can use RPCs like local functions in your program.  Stub code in the local version of that function implements everything that is needed to actually send the request message to the server and receive its reply, from marshalling the function arguments to XXX unraveling the return values.

Server

A Hurd server is a program that provides objects which implement RPC interfaces for users.  The type of objects provided, and thus the RPC interfaces implemented by the server, various depending on the task the server has within the system.

Translator Filesystem

A translator is a server that is attached to the filesystem and implements, not necessarily only, filesystem services.  Translators are also called filesystems.

Bootstrap Object

The bootstrap object is provided to a translator when it is executed. The translator can check the bootstrap object to find out if it was started as a normal Unix process from the command line of the shell, or if it is started as a filesystem server.  In the former case usually only argument parsing is supported.  In the latter case, the translator will attach itself to the filesystem by sending a message to the bootstrap object.

Node

A node is an element of a filesystem, such as a directory, file, symlink, etc.