diff options
author | Laurent Bercot <ska-skaware@skarnet.org> | 2015-01-15 20:14:44 +0000 |
---|---|---|
committer | Laurent Bercot <ska-skaware@skarnet.org> | 2015-01-15 20:14:44 +0000 |
commit | 87c5b2118efcee65eeda3f743d081ea9c2b866d9 (patch) | |
tree | 31ca07d6134adf44bc3d58f4fcf4ea8be9cb7dbb /doc/libs6 | |
parent | cd2500fcc704287c4994a3253b593593c867913e (diff) | |
download | s6-87c5b2118efcee65eeda3f743d081ea9c2b866d9.tar.xz |
Move Unix domain utilities and access control utilites,
as well as the accessrules library, from s6-networking to here
Diffstat (limited to 'doc/libs6')
-rw-r--r-- | doc/libs6/accessrules.html | 331 | ||||
-rw-r--r-- | doc/libs6/ftrigr.html | 268 | ||||
-rw-r--r-- | doc/libs6/ftrigw.html | 100 | ||||
-rw-r--r-- | doc/libs6/index.html | 72 | ||||
-rw-r--r-- | doc/libs6/s6-ftrigrd.html | 80 | ||||
-rw-r--r-- | doc/libs6/s6lock.html | 238 | ||||
-rw-r--r-- | doc/libs6/s6lockd-helper.html | 52 | ||||
-rw-r--r-- | doc/libs6/s6lockd.html | 73 |
8 files changed, 1214 insertions, 0 deletions
diff --git a/doc/libs6/accessrules.html b/doc/libs6/accessrules.html new file mode 100644 index 0000000..bd98b5f --- /dev/null +++ b/doc/libs6/accessrules.html @@ -0,0 +1,331 @@ +<html> + <head> + <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> + <meta http-equiv="Content-Language" content="en" /> + <title>s6: the accessrules library interface</title> + <meta name="Description" content="s6: the accessrules library interface" /> + <meta name="Keywords" content="s6 net accessrules library libs6net unix tcp access control dns ipv4 ipv6" /> + <!-- <link rel="stylesheet" type="text/css" href="http://skarnet.org/default.css" /> --> + </head> +<body> + +<p> +<a href="index.html">libs6</a><br /> +<a href="../">s6</a><br /> +<a href="http://skarnet.org/software/">Software</a><br /> +<a href="http://skarnet.org/">skarnet.org</a> +</p> + +<h1> The <tt>accessrules</tt> library interface </h1> + +<p> + The following functions and structures are declared in the <tt>s6/accessrules.h</tt> header, +and implemented in the <tt>libs6.a</tt> or <tt>libs6.so</tt> library. +</p> + +<h2> General information </h2> + +<p> + <tt>accessrules</tt> is an access control library. It looks up +a key in a user-specified database, then returns a code depending on +whether the database allows access (in which case additional information +can also be returned), denies access, or does not contain the key. +</p> + +<p> + <tt>accessrules</tt> has been designed to be easily extensible to any +database format and any key format. +</p> + +<p> + Check the <tt>s6/accessrules.h</tt> header for the exact definitions. +</p> + +<h2> Data structures </h2> + +<ul> + <li> A <tt>s6_accessrules_result_t</tt> is a scalar that +can have the following values: S6_ACCESSRULES_ERROR, +S6_ACCESSRULES_DENY, S6_ACCESSRULES_ALLOW or S6_ACCESSRULES_NOTFOUND. </li> + <li> A <tt>s6_accessrules_params_t</tt> is a structure containing two +<a href="http://skarnet.org/software/skalibs/libstddjb/stralloc.html">strallocs</a>, +<em>.env</em> and <em>.exec</em>, used to return data contained in the +database when a key has been allowed. The interpretation of this data is +application-defined. </li> +</ul> + +<h2> Function types </h2> + +<h3> Backend lookups </h3> + +<p> + A <tt>s6_accessrules_backend_func_t</tt> is the type of a function +that takes a single key, looks it up in a database, and returns the result. +Namely: +</p> + +<p> +<code>s6_accessrules_result_t f (char const *key, unsigned int keylen, void *handle, s6_accessrules_params_t *params) </code> +</p> + +<p> + <em>f</em> looks up key <em>key</em> of length <em>keylen</em> in the database +represented by <em>handle</em> in an implementation-defined way. It returns a +number that says the key has been allowed, denied or not found, or an error +occurred. If the key has been allowed, <em>f</em> stores additional information +from the database into *<em>params</em>. +</p> + +<p> + Two s6_accessrules_backend_func_t functions are natively implemented: +</p> + +<ul> + <li> <tt>s6_accessrules_backend_fs</tt> takes a <tt>char const *</tt> +<em>handle</em> and interprets it as a base directory to look up <em>key</em> +under, in the format understood by +<a href="../s6-accessrules-cdb-from-fs.html">s6-accessrules-cdb-from-fs</a>. </li> + <li> <tt>s6_accessrules_backend_cdb</tt> takes a <tt>struct cdb *</tt> +<em>handle</em> and looks up <em>key</em> in the +<a href="http://cr.yp.to/cdb.html">CDB</a> it points to. <em>handle</em> must +already be mapped to a CDB file. Such a file can be built with the +<a href="../s6-accessrules-cdb-from-fs.html">s6-accessrules-cdb-from-fs</a> +utility. </li> +</ul> + +<h3> Frontend key checking </h3> + +<p> + A <tt>s6_accessrules_keycheck_func_t</tt> is the type of a function that +takes a user-level key, makes a list of corresponding backend-level keys and +calls a <tt>s6_accessrules_backend_func_t</tt> function until it finds +a match. Namely: +</p> + +<p> +<code>s6_accessrules_result_t f (void const *key, void *handle, s6_accessrules_params_t *params, s6_accessrules_backend_func_t *backend) </code> +</p> + +<p> + <em>f</em> derives a list of low-level keys to check from <em>key</em>. +Then, for each key <em>k</em> of length <em>klen</em> in this list, it calls +<tt>(*backend)(k, klen, handle, params)</tt>, returning *<em>backend</em>'s result if it +is not S6_ACCESSRULES_NOTFOUND. If no match can be found in the whole list, +<em>f</em> finally returns S6_ACCESSRULES_NOTFOUND. +</p> + +<p> + Five s6_accessrules_keycheck_func_t functions are natively implemented: +</p> + +<ul> + <li> +<a name="uidgid" /> + <tt>s6_accessrules_keycheck_uidgid</tt> interprets <em>key</em> as a +<a href="http://skarnet.org/software/skalibs/libstddjb/">diuint</a>, i.e. a +structure containing two unsigned ints. The first one is interpreted as an +uid <em>u</em>, the second one as a gid <em>g</em>. The function first looks +for a <tt>uid/<em>u</em></tt> match; if it cannot find one, it looks for a +<tt>gid/<em>g</em></tt> match. If it cannot find one either, it checks +<tt>uid/default</tt> and returns the result. </li> + <li> +<a name="reversedns" /> + <tt>s6_accessrules_keycheck_reversedns</tt> interprets <em>key</em> +as a string containing a FQDN. Then for each suffix <em>k</em> of <em>key</em>, +starting with <em>key</em> itself and ending with <em>key</em>'s TLD, +it looks up <tt>reversedns/<em>k</em></tt>. The final dot is excluded from +<em>k</em>. If no match can be found, the function checks <tt>reversedns/@</tt> +and returns the result. For instance, if <em>key</em> is "foo.bar.com", +the following strings are looked up, in that order: + <ul> + <li> reversedns/foo.bar.com </li> + <li> reversedns/bar.com </li> + <li> reversedns/com </li> + <li> reversedns/@ </li> + </ul> </li> + <li> +<a name="ip4" /> + <tt>s6_accessrules_keycheck_ip4</tt> interprets <em>key</em> as +4 network-byte-order characters containing an IPv4 address. Then for each +netmask <em>mask</em> from 32 to 0, it constructs the IPv4 network +prefix <em>addr</em> corresponding to that address, and looks up +<tt>ip4/<em>addr</em>_<em>mask</em></tt>. For instance, if <em>key</em> +is "\300\250\001\007", representing the 192.168.1.7 address, the following +strings are looked up, in that order: + <ul> + <li> ip4/192.168.1.7_32 </li> + <li> ip4/192.168.1.6_31 </li> + <li> ip4/192.168.1.4_30 </li> + <li> ip4/192.168.1.0_29 </li> + <li> ip4/192.168.0.0_28 </li> + <li> ip4/192.168.0.0_27 </li> + </ul> + and so on, down to: + <ul> + <li> ip4/192.0.0.0_3 </li> + <li> ip4/192.0.0.0_2 </li> + <li> ip4/128.0.0.0_1 </li> + <li> ip4/0.0.0.0_0 </li> + </ul> + Note that the <tt>ip4/0.0.0.0_0</tt> string is a catch-all key that +matches everything. </li> + <li> +<a name="ip6" /> + <tt>s6_accessrules_keycheck_ip6</tt> interprets <em>key</em> as +16 network-byte-order characters containing an IPv6 address. Then for each +netmask <em>mask</em> from 128 to 0, it constructs the IPv6 network +prefix <em>addr</em> corresponding to that address, +<strong>in canonical form</strong>, +and looks up +<tt>ip6/<em>addr</em>_<em>mask</em></tt>. For instance, if <em>key</em> +is "*\0\024P@\002\b\003\0\0\0\0\0\0\020\006", representing the +2a00:1450:4002:803::1006 address, the following +strings are looked up, in that order: + <ul> + <li> ip6/2a00:1450:4002:803::1006_128 </li> + <li> ip6/2a00:1450:4002:803::1006_127 </li> + <li> ip6/2a00:1450:4002:803::1004_126 </li> + <li> ip6/2a00:1450:4002:803::1000_125 </li> + <li> ip6/2a00:1450:4002:803::1000_124 </li> + <li> ip6/2a00:1450:4002:803::1000_123 </li> + <li> ip6/2a00:1450:4002:803::1000_122 </li> + <li> ip6/2a00:1450:4002:803::1000_121 </li> + <li> ip6/2a00:1450:4002:803::1000_120 </li> + <li> ip6/2a00:1450:4002:803::1000_119 </li> + <li> ip6/2a00:1450:4002:803::1000_118 </li> + <li> ip6/2a00:1450:4002:803::1000_117 </li> + <li> ip6/2a00:1450:4002:803::1000_116 </li> + <li> ip6/2a00:1450:4002:803::1000_115 </li> + <li> ip6/2a00:1450:4002:803::1000_114 </li> + <li> ip6/2a00:1450:4002:803::1000_113 </li> + <li> ip6/2a00:1450:4002:803::_112 </li> + <li> ip6/2a00:1450:4002:803::_111 </li> + </ul> + and so on, down to: + <ul> + <li> ip6/2a00::_11 </li> + <li> ip6/2800::_10 </li> + <li> ip6/2800::_9 </li> + <li> ip6/2000::_8 </li> + <li> ip6/2000::_7 </li> + <li> ip6/2000::_6 </li> + <li> ip6/2000::_5 </li> + <li> ip6/2000::_4 </li> + <li> ip6/2000::_3 </li> + <li> ip6/::_2 </li> + <li> ip6/::_1 </li> + <li> ip6/::_0 </li> + </ul> + Note that the <tt>ip6/::_0</tt> string is a catch-all key that +matches everything. </li> + <li> +<a name="ip46" /> + <tt>s6_accessrules_keycheck_ip46</tt> interprets <em>key</em> as a pointer to an +<a href="http://skarnet.org/software/skalibs/libstddjb/ip46.html">ip46_t</a>, and +behaves either as s6_accessrules_keycheck_ip6 or s6_accessrules_keycheck_ip4, +depending on the type of address *<em>key</em> contains. </li> +</ul> + +<h2> Ready-to-use functions </h2> + + Those functions are mostly macros; they're built by associating a frontend +function with a backend function. + +<p> +<code> s6_accessrules_result_t s6_accessrules_uidgid_cdb +(unsigned int u, unsigned int g, struct cdb *c, +s6_accessrules_params_t *params) </code> <br /> +Checks the *<em>c</em> CDB database for an authorization for uid <em>u</em> +and gid <em>g</em>. If the result is S6_ACCESSRULES_ALLOW, additional +information may be stored into <em>params</em>. +</p> + +<p> +<code> s6_accessrules_result_t s6_accessrules_uidgid_fs +(unsigned int u, unsigned int g, char const *dir, +s6_accessrules_params_t *params) </code> <br /> +Checks the <em>dir</em> base directory for an authorization for uid <em>u</em> +and gid <em>g</em>. If the result is S6_ACCESSRULES_ALLOW, additional +information may be stored into <em>params</em>. +</p> + +<p> +<code> s6_accessrules_result_t s6_accessrules_reversedns_cdb +(char const *name, struct cdb *c, +s6_accessrules_params_t *params) </code> <br /> +Checks the *<em>c</em> CDB database for an authorization for the +<em>name</em> FQDN. If the result is S6_ACCESSRULES_ALLOW, additional +information may be stored into <em>params</em>. +</p> + +<p> +<code> s6_accessrules_result_t s6_accessrules_reversedns_fs +(char const *name, char const *dir, +s6_accessrules_params_t *params) </code> <br /> +Checks the <em>dir</em> base directory for an authorization for the +<em>name</em> FQDN. If the result is S6_ACCESSRULES_ALLOW, additional +information may be stored into <em>params</em>. +</p> + +<p> +<code> s6_accessrules_result_t s6_accessrules_ip4_cdb +(char const *ip4, struct cdb *c, +s6_accessrules_params_t *params) </code> <br /> +Checks the *<em>c</em> CDB database for an authorization for the +<em>ip4</em> IPv4 address (4 network byte order characters). +If the result is S6_ACCESSRULES_ALLOW, additional +information may be stored into <em>params</em>. +</p> + +<p> +<code> s6_accessrules_result_t s6_accessrules_ip4_fs +(char const *ip4, char const *dir, +s6_accessrules_params_t *params) </code> <br /> +Checks the <em>dir</em> base directory for an authorization for the +<em>ip4</em> IPv4 address (4 network byte order characters). +If the result is S6_ACCESSRULES_ALLOW, additional +information may be stored into <em>params</em>. +</p> + +<p> +<code> s6_accessrules_result_t s6_accessrules_ip6_cdb +(char const *ip6, struct cdb *c, +s6_accessrules_params_t *params) </code> <br /> +Checks the *<em>c</em> CDB database for an authorization for the +<em>ip6</em> IPv6 address (16 network byte order characters). +If the result is S6_ACCESSRULES_ALLOW, additional +information may be stored into <em>params</em>. +</p> + +<p> +<code> s6_accessrules_result_t s6_accessrules_ip6_fs +(char const *ip6, char const *dir, +s6_accessrules_params_t *params) </code> <br /> +Checks the <em>dir</em> base directory for an authorization for the +<em>ip6</em> IPv6 address (16 network byte order characters). +If the result is S6_ACCESSRULES_ALLOW, additional +information may be stored into <em>params</em>. +</p> + +<p> +<code> s6_accessrules_result_t s6_accessrules_ip46_cdb +(ip46_t *ip, struct cdb *c, +s6_accessrules_params_t *params) </code> <br /> +Checks the *<em>c</em> CDB database for an authorization for the +<em>ip</em> IP address. +If the result is S6_ACCESSRULES_ALLOW, additional +information may be stored into <em>params</em>. +</p> + +<p> +<code> s6_accessrules_result_t s6_accessrules_ip46_fs +(ip46_t const *ip, char const *dir, +s6_accessrules_params_t *params) </code> <br /> +Checks the <em>dir</em> base directory for an authorization for the +<em>ip</em> IP address. +If the result is S6_ACCESSRULES_ALLOW, additional +information may be stored into <em>params</em>. +</p> + +</body> +</html> diff --git a/doc/libs6/ftrigr.html b/doc/libs6/ftrigr.html new file mode 100644 index 0000000..2c9bf88 --- /dev/null +++ b/doc/libs6/ftrigr.html @@ -0,0 +1,268 @@ +<html> + <head> + <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> + <meta http-equiv="Content-Language" content="en" /> + <title>s6: the ftrigr library interface</title> + <meta name="Description" content="s6: the ftrigr library interface" /> + <meta name="Keywords" content="s6 ftrig notification subscriber listener libftrigr ftrigr library interface" /> + <!-- <link rel="stylesheet" type="text/css" href="http://skarnet.org/default.css" /> --> + </head> +<body> + +<p> +<a href="index.html">libs6</a><br /> +<a href="../">s6</a><br /> +<a href="http://skarnet.org/software/">Software</a><br /> +<a href="http://skarnet.org/">skarnet.org</a> +</p> + +<h1> The <tt>ftrigr</tt> library interface </h1> + +<p> + The <tt>ftrigr</tt> library provides an API for listeners, i.e. +programs that want to subscribe to fifodirs and be instantly +notified when the proper sequence of events happens. +</p> + +<h2> Programming </h2> + +<p> + Check the <tt>s6/ftrigr.h</tt> header for the +exact function prototypes. +</p> + +<p> + Make sure your application is not disturbed by children it doesn't +know it has. This means paying some attention to the SIGCHLD handler, +if any, and to the way you perform <tt>waitpid()</tt>s. The best +practice is to use a +<a href="http://skarnet.org/software/skalibs/libstddjb/selfpipe.html">self-pipe</a> +to handle SIGCHLD (as well as other signals the application needs to trap), +and to <em>always</em> use <tt>wait_nohang()</tt> to reap children, +simply ignoring pids you don't know. +</p> + +<p> + If your (badly programmed) application has trouble handling unknown +children, consider using a ftrigrd service. +</p> + +<h3> A programming example </h3> + +<p> + The <tt>src/pipe-tools/s6-ftrig-listen1.c</tt> and +<tt>src/supervision/s6-svwait.c</tt> files in the s6 package, +for instance, illustrate how to use the ftrigr library. +</p> + + +<h3> Synchronous functions with a specified maximum execution time </h3> + +<ul> + <li> Synchronous functions take a <tt>tain_t const *</tt> +(<em>deadline</em>) parameter and a <tt>tain_t *</tt> (<em>stamp</em>) +parameter. Those are pointers to tain_t structures containing absolute times; +the former represents a deadline (in most cases, this time will be in the +future) and the latter must be an accurate enough timestamp. These +structures can be filled using the <tt>tain_</tt> primitives declared in +<a href="http://skarnet.org/software/skalibs/libstddjb/tai.html">skalibs/tai.h</a>. </li> + <li> ("Accurate enough" means that <strong>no blocking system call must have +been made</strong> since the last time <em>stamp</em> was updated (by +<tt>tain_now(&stamp)</tt>). It's a good policy to always update +<em>stamp</em> right after a (potentially) blocking system call like +<tt>select()</tt> returns. And unless the application is extremely CPU-intensive +(think calculus for physicists or astronomers) updating <em>stamp</em> more +frequently is unnecessary.) </li> + <li> If such a synchronous function still hasn't returned when the deadline +occurs, then it will immediately return a failure code and set errno to ETIMEDOUT. +It is possible to pass null pointers to the function instead of pointers to +tain_t structures, in which case the function will never timeout. </li> + <li> If a timeout occurs, the library does not guarantee proper interprocess +communication later on; the application should either die, or at least close +the communication channel and open a new one. </li> + <li> If any waiting occurred, the <em>stamp</em> structure is automatically +updated by the called function, so it always represents an accurate enough estimation +of the current time. This allows the programmer to call several such functions +in a sequence without modifying the <em>deadline</em> and <em>stamp</em> +parameters: then the whole sequence is bound in execution time. </li> + <li> This is a general safety mechanism implemented in +<a href="http://skarnet.org/software/skalibs/libunixonacid/">libunixonacid</a>: +in interprocess communication, purely synchronous primitives are dangerous +because they make the calling process rely on proper behaviour of the called +process. Giving synchronous primitives the ability to timeout allows developers +to write reliable programs even when interacting with software they have no +control on. </li> +</ul> + + +<h3> Starting and ending a session </h3> + +<pre> +ftrigr_t a = FTRIGR_ZERO ; +tain_t deadline, stamp ; + +tain_now(&stamp) ; +tain_addsec(&deadline, &stamp, 2) + +// char const *path = FTRIGR_IPCPATH ; +// ftrigr_start(&a, path, &deadline, &stamp) ; +ftrigr_startf(&a, &deadline, &stamp) ; +</pre> + +<p> +<tt>ftrigr_start</tt> starts a session with a ftrigrd service listening on +<em>path</em>. <br /> +<tt>ftrigr_startf</tt> starts a session with a ftrigrd process as a child +(which is the simplest usage). <br /> +<tt>a</tt> is a ftrigr_t structure that must be declared in the stack and +initialized to FTRIGR_ZERO. +<tt>stamp</tt> must be an accurate enough timestamp. <br /> +If the session initialization fails, the function returns 0 and errno is set; +else the function returns 1. +</p> +<p> +If the absolute time <tt>deadline</tt> is reached and the function +has not returned yet, it immediately returns 0 with errno set to ETIMEDOUT. + +Only local interprocess communications are involved; unless your system is +heavily overloaded, the function should return near-instantly. One or two +seconds of delay between <tt>stamp</tt> and <tt>deadline</tt> should be +enough: if the function takes more than that to return, then there is a +problem with the underlying processes. +</p> + +<p> + You can have more than one session open in parallel, by declaring +several distinct <tt>ftrigr_t</tt> structures and calling +<tt>ftrigr_startf</tt> (or <tt>ftrigr_start</tt>) more than once. +However, this is useless, since one single session can handle +virtually as many concurrent fifodirs as your application needs. +</p> + +<pre> +ftrigr_end(&a) ; +</pre> + +<p> +<tt>ftrigr_end</tt> frees all the resources used by the session. The +<tt>a</tt> structure is then reusable for another session. +</p> + +<h3> Subscribing to a fifodir </h3> + +<pre> +char const *path = "/var/lib/myservice/fifodir" ; +char const *re = "a.*b|c*d" ; +uint32 options = 0 ; + +uint16 id = ftrigr_subscribe (&a, path, re, options, &deadline, &stamp) ; +</pre> + +<p> +<tt>ftrigr_subscribe</tt> instructs the +<a href="s6-ftrigrd.html">s6-ftrigrd daemon</a>, related to the open +session represented by the <tt>a</tt> structure, to subscribe to the +<tt>path</tt> fifodir, and to notify the application when it receives +a series of events that matches the <tt>re</tt> regexp. +<tt>options</tt> can be 0 or FTRIGR_REPEAT. If it is 0, the daemon will +automatically unsubscribe from <tt>path</tt> once <tt>re</tt> has been +matched by a series of events. If it is FTRIGR_REPEAT, it will remain +subscribed until told otherwise. +</p> + +<p> + <tt>ftrigr_subscribe()</tt> returns 0 and sets errno in case of failure, or +a nonzero 16-bit number identifying the subscription in case of success. +</p> + +<p> +<tt>ftrigr_subscribe</tt> should return near-instantly, but if +<em>deadline</em> is reached, it will return 0 ETIMEDOUT. If +<tt>ftrigr_subscribe</tt> returns successfully, then the +s6-ftrigrd daemon is guaranteed to be listening on <tt>path</tt>, +and events can be sent without the risk of a race condition. +</p> + +<h3> Synchronously waiting for events </h3> + +<pre> +uint16 list[1] ; +unsigned int n = 1 ; +char trigger ; +list[0] = id ; + +// r = ftrigr_wait_and(&a, list, n, &deadline) ; +r = ftrigr_wait_or(&a, list, n, &deadline, &trigger) ; +</pre> + +<p> + <tt>ftrigr_wait_and()</tt> waits for <em>all</em> the <tt>n</tt> fifodirs +whose ids are listed in <tt>list</tt> to receive an event. It returns -1 +in case of error or timeout, or a non-negative integer in case of success. <br /> + <tt>ftrigr_wait_or()</tt> waits for <em>one</em> of the <tt>n</tt> fifodirs +whose ids are listed in <tt>list</tt> to receive an event. It returns -1 +in case of error or timeout; if it succeeds, the return value is the +position in <tt>list</tt>, starting at 0, of the identifier that received +an event; and <tt>trigger</tt> is set to the character that triggered that +event, i.e. the last character of a sequence that matched the regular +expression <tt>re</tt> used in the subscription. +</p> + +<h3> Asynchronously waiting for events </h3> + +<p> +<em> (from now on, the functions are listed with their prototypes instead +of usage examples.) </em> +</p> + +<pre> +int ftrigr_fd (ftrigr_t const *a) +</pre> + +<p> + Returns a file descriptor to select on for reading. Do not +<tt>read()</tt> it though. +</p> + +<pre> +int ftrigr_update (ftrigr_t *a) +</pre> + +<p> + Call this function whenever the fd checks readability: it will +update <em>a</em>'s internal structures with information from the +<a href="s6-ftrigrd.html">s6-ftrigrd</a> daemon. It returns -1 if an error +occurs; in case of success, it returns the number of identifiers for +which something happened. +</p> + +<p> + When <tt>ftrigr_update</tt> returns, +<tt>genalloc_s(uint16, &a->list)</tt> points to an array of +<tt>genalloc_len(uint16, &a->list)</tt> 16-bit unsigned +integers. Those integers are ids waiting to be passed to +<tt>ftrigr_check</tt>. +</p> + +<pre> +int ftrigr_check (ftrigr_t *a, uint16 id, char *what) +</pre> + +<p> + Checks whether an event happened to <em>id</em>. Use after a +call to <tt>ftrigr_update()</tt>. +</p> + +<ul> + <li> If an error occurred, returns -1 and sets errno. The error +number may have been transmitted from +<a href="s6-ftrigrd.html">s6-ftrigrd</a>. </li> + <li> If no notification happened yet, returns 0. </li> + <li> If something happened, writes the character that triggered the +latest notification into <em>what</em> and returns the number of +times that an event happened to this identifier since the last +call to <tt>ftrigr_check()</tt>. </li> +</ul> + +</body> +</html> diff --git a/doc/libs6/ftrigw.html b/doc/libs6/ftrigw.html new file mode 100644 index 0000000..b0feb31 --- /dev/null +++ b/doc/libs6/ftrigw.html @@ -0,0 +1,100 @@ +<html> + <head> + <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> + <meta http-equiv="Content-Language" content="en" /> + <title>s6: the ftrigw library interface</title> + <meta name="Description" content="s6: the ftrigw library interface" /> + <meta name="Keywords" content="s6 ftrig notification notifier writer libftrigw ftrigw library interface" /> + <!-- <link rel="stylesheet" type="text/css" href="http://skarnet.org/default.css" /> --> + </head> +<body> + +<p> +<a href="index.html">libs6</a><br /> +<a href="../">s6</a><br /> +<a href="http://skarnet.org/software/">Software</a><br /> +<a href="http://skarnet.org/">skarnet.org</a> +</p> + +<h1> The <tt>ftrigw</tt> library interface </h1> + +<p> + The <tt>ftrigw</tt> library provides an API for notifiers, i.e. +programs that want to regularly announce what they're doing. +</p> + +<p> + Notifiers should create a fifodir in a hardcoded place in the +filesystem, and document its location. Listeners will then be +able to subscribe to that fifodir, and receive the events. +</p> + +<h2> Programming </h2> + +<p> + Check the <tt>s6/ftrigw.h</tt> header for the +exact function prototypes. +</p> + +<h3> Creating a fifodir </h3> + +<pre> +char const *path = "/var/lib/myservice/fifodir" ; +int gid = -1 ; +int forceperms = 0 ; +int r = ftrigw_fifodir_make(path, gid, forceperms) ; +</pre> + +<p> +<tt>ftrigw_fifodir_make</tt> creates a fifodir at the <tt>path</tt> location. +It returns 0, and sets errno, if an error occurs. +It returns 1 if it succeeds. <br /> +If a fifodir, owned by the user, already exists at <tt>path</tt>, and +<tt>forceperms</tt> is zero, then <tt>ftrigw_fifodir_make</tt> immediately +returns a success. If <tt>forceperms</tt> is nonzero, then +it tries to adjust <tt>path</tt>'s permissions before returning. +</p> + +<p> +If <tt>gid</tt> is negative, then <tt>path</tt> is created "public". +Any listener will be able to subscribe to <tt>path</tt>. +If <tt>gid</tt> is nonnegative, then <tt>path</tt> is created "private". +Only processes belonging to group <tt>gid</tt> will be able to +subscribe to <tt>path</tt>. +</p> + +<h3> Sending an event </h3> + +<pre> +char event = 'a' ; +r = ftrigw_notify(path, event) ; +</pre> + +<p> +<tt>ftrigw_notify</tt> sends <tt>event</tt> to all the processes that are +currently subscribed to <tt>path</tt>. +It returns -1 if an error occurs, or the number of successfully notified +processes. +</p> + +<h3> Cleaning up </h3> + +<p> +When stray KILL signals hit <a href="s6-ftrigrd.html">s6-ftrigrd</a> processes, +1. it's a sign of incorrect system administration, 2. they can leave +unused named pipes in the fifodir. It's the fifodir's owner's job, i.e. +the notifier's job, to periodically do some housecleaning and remove +those unused pipes. +</p> + +<pre> +r = ftrigw_clean(path) ; +</pre> + +<p> +<tt>ftrigw_clean</tt> cleans <tt>path</tt>. It returns 0, and sets errno, +if it encounters an error. It returns 1 if it succeeds. +</p> + +</body> +</html> diff --git a/doc/libs6/index.html b/doc/libs6/index.html new file mode 100644 index 0000000..9fe7e65 --- /dev/null +++ b/doc/libs6/index.html @@ -0,0 +1,72 @@ +<html> + <head> + <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> + <meta http-equiv="Content-Language" content="en" /> + <title>s6: the s6 library interface</title> + <meta name="Description" content="s6: the s6 library interface" /> + <meta name="Keywords" content="s6 s6 libs6 library libs6net" /> + <!-- <link rel="stylesheet" type="text/css" href="http://skarnet.org/default.css" /> --> + </head> +<body> + +<p> +<a href="../">s6</a><br /> +<a href="http://skarnet.org/software/">Software</a><br /> +<a href="http://skarnet.org/">skarnet.org</a> +</p> + +<h1> The <tt>s6</tt> library interface </h1> + +<h2> General information </h2> + +<p> + <tt>libs6</tt> is a collection of utility +C interfaces, used in the s6 executables. +</p> + +<h2> Compiling </h2> + +<ul> + <li> Make sure the s6 headers, as well as the skalibs headers, +are visible in your header search path. </li> + <li> Use <tt>#include <s6/s6.h></tt> </li> +</ul> + +<h2> Linking </h2> + +<ul> + <li> Make sure the s6 libraries, as well as the skalibs +libraries, are visible in your library search path. </li> + <li> Link against <tt>-ls6</tt> and <tt>-lskarnet</tt>. +If you're using socket functions (which is the case with +<a href="ftrigr.html">libftrigr</a>, for instance, add +<tt>`cat $sysdeps/socket.lib`</tt> to your command line. +If you're using timed functions involving TAI timestamps +(which is also the case with <a href="ftrigr.html">libftrigr</a> +for instance), add +<tt>`cat $sysdeps/tainnow.lib`</tt>. <tt>$sysdeps</tt> +stands for your skalibs sysdeps directory. </li> +</ul> + +<h2> Programming </h2> + +<p> + The <tt>s6/s6.h</tt> header is actually a +concatenation of other headers: +the libs6net is separated into several modules, each of them with its +own header. +</p> + +<ul> + <li> The <a href="accessrules.html">s6/accessrules.h</a> header +provides functions to check credentials against configuration files. </li> + <li> The <a href="ftrigr.html">s6/ftrigr.h</a> header provides +functions to subscribe to fifodirs and be notified of events. </li> + <li> The <a href="ftrigw.html">s6/ftrigw.h</a> header provides +functions to manage fifodirs and send notifications to them. </li> + <li> The <a href="s6lock.html">s6/s6lock.h</a> header provides +functions to acquire locks with a timeout. </li> +</ul> + +</body> +</html> diff --git a/doc/libs6/s6-ftrigrd.html b/doc/libs6/s6-ftrigrd.html new file mode 100644 index 0000000..4bbfc69 --- /dev/null +++ b/doc/libs6/s6-ftrigrd.html @@ -0,0 +1,80 @@ +<html> + <head> + <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> + <meta http-equiv="Content-Language" content="en" /> + <title>s6: the s6-ftrigrd program</title> + <meta name="Description" content="s6: the s6-ftrigrd program" /> + <meta name="Keywords" content="s6 command s6-ftrigrd program internal libexec fifodir regexp subscribe notification listener" /> + <!-- <link rel="stylesheet" type="text/css" href="http://skarnet.org/default.css" /> --> + </head> +<body> + +<p> +<a href="index.html">libs6</a><br /> +<a href="../">s6</a><br /> +<a href="http://skarnet.org/software/">Software</a><br /> +<a href="http://skarnet.org/">skarnet.org</a> +</p> + +<h1> The s6-ftrigrd program </h1> + +<p> +s6-ftrigrd is a helper program that manages a set of subscriptions to fifodirs as well +as regular expressions on events. It takes orders from its client program that controls +it via the <a href="ftrigr.html">ftrigr library</a>, and notifies it when desired +events happen. +</p> + +<h2> Interface </h2> + +<p> + s6-ftrigrd is not meant to be called directly. +</p> + +<ul> + <li> If the client program uses <tt>ftrigr_startf()</tt>, it spawns an instance of +s6-ftrigrd as a child. s6-ftrigrd's stdin is a pipe reading from the client; its +stdout is a pipe writing to the client; its stderr is the same as the client's; and +there's an additional pipe from s6-ftrigrd to the client, used for asynchronous +notifications. </li> + <li> If the client program uses <tt>ftrigr_start()</tt>, then it tries to connect +to a Unix domain socket. A ftrigrd <a href="../localservice.html">local service</a> should be listening to that +socket, i.e. a Unix domain superserver such as +<a href="s6-ipcserver.html">s6-ipcserver</a> +spawning a s6-ftrigrd program on every connection. Then a s6-ftrigrd instance is created +for the client. </li> + <li> When the client uses <tt>ftrigr_end()</tt>, or closes s6-ftrigrd's stdin in +any way, s6-ftrigrd exits 0. </li> +</ul> + +<p> + s6-ftrigrd handles the grunt work of creating fifos in a +<a href="fifodir.html">fifodir</a> for a subscriber. It also wakes up on every +event, and compares the chain of events it received on a given fifodir with the +client-provided regexp. If the chain of events matches the regexp, it notifies +the client. +</p> + +<h2> Notes </h2> + +<p> + The connection management between the client and s6-ftrigrd is entirely done +by the <a href="http://skarnet.org/software/skalibs/libunixonacid/skaclient.html">skaclient</a> +library. +</p> + +<p> + s6-ftrigrd is entirely asynchronous. It stores unread notifications into heap +memory; it can grow in size if there are a lot of events and the client fails +to read them. To avoid uncontrolled growth, make sure your client calls +<tt>ftrigr_update()</tt> as soon as <tt>ftrigr_fd()</tt> becomes readable. +</p> + +<p> + A s6-ftrigrd instance can only handle up to FTRIGRD_MAX (defined in <tt>s6/ftrigr.h</tt>) +subscriptions at once. By default, this number is 1000, which is more than enough for +any reasonable system. +</p> + +</body> +</html> diff --git a/doc/libs6/s6lock.html b/doc/libs6/s6lock.html new file mode 100644 index 0000000..ca22fe4 --- /dev/null +++ b/doc/libs6/s6lock.html @@ -0,0 +1,238 @@ +<html> + <head> + <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> + <meta http-equiv="Content-Language" content="en" /> + <title>s6: the s6lock library interface</title> + <meta name="Description" content="s6: the s6lock library interface" /> + <meta name="Keywords" content="s6 timed lock s6lock libs6 library interface" /> + <!-- <link rel="stylesheet" type="text/css" href="http://skarnet.org/default.css" /> --> + </head> +<body> + +<p> +<a href="index.html">libs6</a><br /> +<a href="../">s6</a><br /> +<a href="http://skarnet.org/software/">Software</a><br /> +<a href="http://skarnet.org/">skarnet.org</a> +</p> + +<h1> The <tt>s6lock</tt> library interface </h1> + +<h2> General information </h2> + +<p> + <tt>s6lock</tt> is a C interface to timed locks. Unix natively provides +locks, but the locking primitives are synchronous, so either they are +unbounded in execution time or they require polling. s6lock provides +poll-free locks that can timeout during attempted acquisition. +</p> + +<h2> Programming </h2> + +<ul> + <li> Check the <tt>s6/s6lock.h</tt> header +for the prototypes. The functions documented here are +often simplified macros, for instance relying on the STAMP global variable +to hold the current time. Fully reentrant functions with more control +options are usually available. </li> + <li> Given the nature of the s6lock library, it makes sense to use a +<a href="../localservice.html">s6lockd service</a> concurrently +accessed by several applications using such locks to gate shared +resources. </li> + <li> If you're not using a s6lockd service, +make sure your application is not disturbed by children it doesn't +know it has. Using nonblocking waits, ignoring pids you don't know, and +using a +<a href="http://skarnet.org/software/skalibs/libstddjb/selfpipe.html">self-pipe</a> +if your application is built around an event loop, are good programming +practices. </li> +</ul> + +<h3> Starting and ending a session </h3> + +<pre> +s6lock_t a = S6LOCK_ZERO ; +tain_t deadline ; + +tain_now_g() ; +tain_addsec_g(&deadline, 2) + +char const *path = S6LOCK_IPCPATH ; +s6lock_start_g(&a, path, &deadline) ; +// char const *lockdir = "/tmp/lock" ; +// s6lock_startf_g(&a, lockdir, &deadline) ; +</pre> + +<p> +<tt>s6lock_start_g</tt> starts a session by connecting to a s6lockd service +listening on <em>path</em>. The working directory is set by the administrator +of the service. <br /> +<tt>s6lock_startf_g</tt> starts a session with a s6lockd process as a child, +using <em>lockdir</em> as its working directory. +<br /> +<tt>a</tt> is a s6lock_t structure that must be declared in the stack and +initialized to S6LOCK_ZERO. +If the session initialization fails, the function returns 0 and errno is set; +else the function returns 1. +</p> +<p> +If the absolute time <tt>deadline</tt> is reached and the function +has not returned yet, it immediately returns 0 with errno set to ETIMEDOUT. + +Only local interprocess communications are involved; unless your system is +heavily overloaded, the function should return near-instantly. One or two +seconds of delay between the current time and <tt>deadline</tt> should be +enough: if the function takes more than that to return, then there is a +problem with the underlying processes. +</p> + +<p> + You can have more than one session open in parallel, by declaring +several distinct <tt>s6lock_t</tt> structures and calling +<tt>s6lock_startf_g</tt> (or <tt>s6lock_start_g</tt>) more than once. +However, one single session can handle +virtually as many concurrent locks as your application needs, so +opening several sessions is only useful if you need to acquire locks +in various distinct lock directories. +</p> + +<pre> +s6lock_end(&a) ; +</pre> + +<p> +<tt>s6lock_end</tt> frees all the resources used by the session. The +<tt>a</tt> structure is then reusable for another session. +</p> + +<h3> Acquiring and releasing locks </h3> + +<pre> +uint16 id ; +char const *file = "lockfile" ; +tain_t limit ; +tain_t deadline ; + +int r = s6lock_acquire_sh_g (&a, &id, file, &limit, &deadline) ; +/* int r = s6lock_acquire_ex_g (&a, &id, file, &limit, &deadline) ; */ +r = s6lock_release_g(&a, id, &deadline) ; +</pre> + +<p> +<tt>s6lock_acquire_sh_g</tt> instructs the +<a href="s6lockd.html">s6lockd daemon</a>, related to the open +session represented by the <tt>a</tt> handle, to try and acquire a +shared lock on the +<em>file</em> file located under that daemon's working directory +(typically <tt>/var/lock</tt>). <em>file</em> will be interpreted as +relative to the daemon's working directory even if it starts with a +slash; however, slashes in the middle of <em>file</em> are likely to +result in an error. +</p> + +<p> +<em>limit</em> and <em>deadline</em> are two absolute dates. +<em>deadline</em> is a deadline for the execution of the +function: if by <em>deadline</em> the function has not returned, +then it instantly returns 0 and sets errno to ETIMEDOUT. The +function is normally near-instantaneous, so <em>deadline</em> can +be very close in the future and serves only as a protection against +malicious servers. <em>limit</em> is the acquisition deadline: if +by <em>limit</em> the daemon still has not been able to acquire a lock +on <em>file</em>, then it will report a timeout to the client. +</p> + +<p> +The function returns 1 in case of success, or 0 if an error occurs, +with errno set to a suitable value. If it succeeds, then a 16-bit +number is stored into *<em>id</em>; this number serves as an identifier +for this lock. +</p> + +<p> +<tt>s6lock_acquire_ex_g</tt> works just like <tt>s6lock_acquire_sh_g</tt>, +except that the daemon tries to acquire an exclusive lock. +</p> + +<p> +<tt>s6lock_release_g</tt> releases the lock identified by <em>id</em>. +It normally returns 1. It can return 0 with errno set to a suitable +value if it fails. <em>id</em> is not valid after the corresponding +lock has been released. The function normally returns instantly, with +<em>deadline</em> as a safeguard. +</p> + +<h3> Asynchronously waiting for locks </h3> + +<p> +<em> (from now on, the functions are listed with their prototypes instead +of usage examples.) </em> +</p> + +<pre> +int s6lock_fd (s6lock_t const *a) +</pre> + +<p> + Returns a file descriptor to select on for reading. Do not +<tt>read()</tt> it though. +</p> + +<pre> +int s6lock_update (s6lock_t *a) +</pre> + +<p> + Call this function whenever the fd checks readability: it will +update <em>a</em>'s internal structures with information from the +<a href="s6lockd.html">s6lockd</a> daemon. It returns -1 if an error +occurs; in case of success, it returns the number of identifiers for +which something happened. +</p> + +<p> + When <tt>s6lock_update</tt> returns, +<tt>genalloc_s(uint16, &a->list)</tt> points to an array of +<tt>genalloc_len(uint16, &a->list)</tt> 16-bit unsigned +integers. Those integers are ids waiting to be passed to +<tt>s6lock_check</tt>. +</p> + +<pre> +int s6lock_check (s6lock_t *a, uint16 id, char *what) +</pre> + +<p> + Checks whether the lock identified by <em>id</em> has +been acquired. Use after a call to <tt>s6lock_update()</tt>. +</p> + +<ul> + <li> If an error occurred, returns -1 and sets errno. The error +number may have been transmitted from +<a href="s6lockd.html">s6lockd</a>. </li> + <li> If the lock has not been acquired yet, returns 0. </li> + <li> If the lock has been acquired, returns 1. </li> +</ul> + +<h3> Synchronously waiting for locks </h3> + +<p> +<code> int s6lock_wait_or_g (s6lock_t *a, uint16 const *idlist, unsigned int n, tain_t const *deadline) </code> <br /> +Synchronously waits for <em>one</em> of the locks represented by the array pointed to +by <em>idlist</em> of length <em>n</em> to be acquired. Returns -1 if it fails, +or a nonnegative number on success, which is the index in <em>idlist</em> of the +acquired lock's id. If no result has been obtained by <em>deadline</em>, the +function returns -1 ETIMEDOUT. +</p> + +<p> +<code> int s6lock_wait_and_g (s6lock_t *a, uint16 const *idlist, unsigned int n, tain_t const *deadline) </code> <br /> +Synchronously waits for <em>all</em> of the locks represented by the array pointed to +by <em>idlist</em> of length <em>n</em> to be acquired. Returns -1 if it fails and +0 if it succeeds. If no result has been obtained by <em>deadline</em>, the +function returns -1 ETIMEDOUT. +</p> + +</body> +</html> diff --git a/doc/libs6/s6lockd-helper.html b/doc/libs6/s6lockd-helper.html new file mode 100644 index 0000000..2c54e5c --- /dev/null +++ b/doc/libs6/s6lockd-helper.html @@ -0,0 +1,52 @@ +<html> + <head> + <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> + <meta http-equiv="Content-Language" content="en" /> + <title>s6: the s6lockd-helper internal program</title> + <meta name="Description" content="s6: the s6lockd-helper internal program" /> + <meta name="Keywords" content="s6 s6lockd-helper lockd asynchronous timed lock daemon helper" /> + <!-- <link rel="stylesheet" type="text/css" href="http://skarnet.org/default.css" /> --> + </head> +<body> + +<a href="index.html">libs6</a><br /> +<a href="../">s6</a><br /> +<a href="http://skarnet.org/software/">Software</a><br /> +<a href="http://skarnet.org/">skarnet.org</a><p /> + +<h1> The <tt>s6lockd-helper</tt> program </h1> + +<p> +<tt>s6lockd-helper</tt> is a helper program for the s6lock daemon. +It just acquires a lock and holds it until it is killed or told to +exit by its parent daemon. +</p> + +<h2> Interface </h2> + +<p> + s6lockd-helper is not meant to be invoked directly by the user: +it will be spawned by the +<a href="s6lockd.html">s6lockd</a> program. +</p> + +<h2> Notes </h2> + +<ul> + <li> s6lockd-helper blocks on lock acquisition until it succeeds. It then +notifies its parent. It exits when its parent tells him to (i.e. when the +client asks for lock release). During the lock acquisition phase, it can +be killed if its parent detects a timeout. </li> + <li> One s6lockd-helper process per lock is the only way (apart from +threads) to implement timed lock acquisition. This can lead to a lot of +s6lockd-helper processes, but this is not a problem: + <ul> + <li> Processes are not a scarce resource. Today's schedulers work in O(1), +i.e. a sleeping process takes no scheduling time at all. </li> + <li> s6lockd-helper is extremely tiny. Every instance should use up at +most one or two pages of non-sharable memory. </li> + </ul> </li> +</ul> + +</body> +</html> diff --git a/doc/libs6/s6lockd.html b/doc/libs6/s6lockd.html new file mode 100644 index 0000000..7db76be --- /dev/null +++ b/doc/libs6/s6lockd.html @@ -0,0 +1,73 @@ +<html> + <head> + <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> + <meta http-equiv="Content-Language" content="en" /> + <title>s6: the s6lockd internal program</title> + <meta name="Description" content="s6: the s6lockd internal program" /> + <meta name="Keywords" content="s6 s6lockd lockd asynchronous timed lock daemon" /> + <!-- <link rel="stylesheet" type="text/css" href="http://skarnet.org/default.css" /> --> + </head> +<body> + +<a href="index.html">libs6</a><br /> +<a href="../">s6</a><br /> +<a href="http://skarnet.org/software/">Software</a><br /> +<a href="http://skarnet.org/">skarnet.org</a><p /> + +<h1> The <tt>s6lockd</tt> program </h1> + +<p> +<tt>s6lockd</tt> is the s6lock daemon. It is a program that manages +a set of lock files in a given directory, and associated timeouts. +</p> + +<h2> Interface </h2> + +<p> + s6lockd does not fork, does not background itself automatically, +and does not use syslog. It is not meant to be run directly by the +user: it will be spawned by the +<a href="s6lock.html">s6lock client library</a>. +</p> + +<p> + There are 2 ways to use s6lockd: +</p> + +<ol> + <li> Use the <tt>s6lock_startf()</tt> library call. +A <tt>s6lockd</tt> child will then be spawned from your +calling process, and automatically reaped when you call +<tt>s6lock_end()</tt>. It requires care with applications that +trap SIGCHLD. It also requires care with lock file permissions: +a s6lockd instance might not be able +to open a lock file created by a former instance run by another +client with different permissions. </li> + <li> Use the <tt>s6lock_start()</tt> library call, together with a +<a href="../localservice.html">s6lockd service</a>. +For once, <em>this is the recommended setup</em>: s6lockd creates empty +lock files, and having all s6lockd instances run under the same user +simplifies permissions management considerably. </li> + </li> +</ol> + +<p> +When run as a service, s6lockd has no "standalone" mode: it is +designed to work with a Unix +domain superserver, like +<a href="../s6-ipcserver.html">s6-ipcserver</a>. +s6lockd follows the <a href="http://cr.yp.to/proto/ucspi.txt">UCSPI</a> +interface, it can be directly executed from the superserver. +</p> + +<h2> Notes </h2> + +<ul> + <li> Unix does not natively provide a way to stop blocking on a lock +acquisition after a timeout. To emulate such behaviour, s6lockd actually +spawns a <a href="s6lockd-helper.html">s6lockd-helper</a> child per +requested lock. </li> +</ul> + +</body> +</html> |