Re: s6, listen(8), etc.

2016-09-06 Thread Laurent Bercot

On 06/09/2016 10:42, Jonathan de Boyne Pollard wrote:

One dictum is that if you're using the "LISTEN" protocol for any
UCSPI use-case, you are doing it wrong.  The name "LISTEN" in
"LISTEN_FDS" is a big clue.  It's not for accepted socket file
descriptors.  It's for listening ones.

UCSPI deals in accepted connections, conversely.


 That's right; sorry for entertaining the confusion. I was focusing on the
"pass open fds other than 0, 1 and 2 from the caller to the daemon" aspect,
without considering the nature of the fds.
 I am still of the opinion that the nature of the fds should be a
convention between the caller and the daemon. The most interesting thing
about UCSPI is that it only handles byte streams, so any fd you can
read() from and write() to generally works.

 A socket that hasn't been obtained by accept() is different in that it
has a lot of states (created, bound, listening, and maybe more) in which
you still can't read/write. Each of those states is dynamically testable,
but it's a lot cleaner if the daemon knows what state the fd it receives
is supposed to be in.



If you think that "here's a bunch of file descriptors" is the
protocol, then you've missed a subtlety.  The protocol is that the
list of file descriptors is *ordered*, by the system
administrator/package writer.


 Oh, yes, of course it's ordered. It's a list, not a set - else you
could never make it work without labels. I just find it ugly to test
the type of the received fd dynamically, see below.



 They could equally well define something like "You
specify my control listening FIFO first, my TCP4 service listening
socket second, and my TCP6 service listening socket third in the
list.".  How the ordered list of file descriptors is treated is
defined by the service programs themselves.


 Yes. That was the point I was making: the simplest possible API is a
hardcoded convention from the daemon. LISTEN_FDS just makes it less
flexible, since the control listening FIFO will be 3, the TCP4 listening
socket will be 4 and the TCP6 listening socket will be 5, and the
daemon is not free to use those for another purpose.

 But Daniel's answer, as I understood it, was that some daemons may want
to get *several* fds for the same service: for instance, to listen to a
dynamically specified number of IPv4 addresses in order to provide TCP4
service to all of them. In that case, it is not possible anymore to rely
on fixed fd numbers: and you need to either dynamically test the type
of the fds you receive, or use a "purpose label -> set of fds with that
purpose" map. The latter is a lot more aesthetically pleasing to me than
the former.

--
 Laurent



Re: s6, listen(8), etc.

2016-09-06 Thread Jonathan de Boyne Pollard

Laurent Bercot:

fds 6 and 7 are only used for UCSPI clients, which are a very minor 
subset of the programs you'd want to use that mechanism with.



Laurent Bercot:

I don't want the caller to tell me "here's a bunch of fds, you sort 
them out": that's just laziness.



Just so that everyone is not operating under any more misapprehensions:

One dictum is that if you're using the "LISTEN" protocol for any UCSPI 
use-case, you are doing it wrong.  The name "LISTEN" in "LISTEN_FDS" is 
a big clue.  It's not for accepted socket file descriptors.  It's for 
listening ones.


UCSPI deals in accepted connections, conversely.  The systemd people 
reinvented their own, pretty poor, protocol for accepted connections.  
It is not the "LISTEN" protocol.  In 2015 I tried to point them at UCSPI 
where there's years to decades of existing practice, doco, and 
implementation (including GNU inetd!) to gain from.  See 
https://lists.freedesktop.org/archives/systemd-devel/2015-June/033299.html


(The UCSPI FGA is now http://jdebp.eu./FGA/UCSPI.html , by the way.)

If you think that "here's a bunch of file descriptors" is the protocol, 
then you've missed a subtlety.  The protocol is that the list of file 
descriptors is *ordered*, by the system administrator/package writer.  
The systemd manual pages explain that it's the order that the various 
ListenXXX directives occur in the .INI file.  (systemd treats .INI files 
as ordered in various ways, of which this is one.)  In the nosh toolset, 
it's simply the order in which you chain together the chain-loading 
*-listen tools.  Each tool appends a further listening file descriptor 
to the end of the list that it begins execution with.


So whilst in the wild generally programs just scan the whole list 
looking for the first/last file descriptor whose type (FIFO, socket 
address family, and so on) they like, on the basis that they are 
generally only looking for one file descriptor of any type, this is an 
interpretation that's defined by the particular server programs 
concerned.  They could equally well define something like "You specify 
my control listening FIFO first, my TCP4 service listening socket 
second, and my TCP6 service listening socket third in the list.".  How 
the ordered list of file descriptors is treated is defined by the 
service programs themselves.




Re: s6, listen(8), etc.

2016-09-05 Thread Daniel Kahn Gillmor
On Mon 2016-09-05 02:48:54 -0400, Jonathan de Boyne Pollard wrote:
> Daniel Kahn Gillmor:
>
>>  #!/bin/sh
>>  mkdir -p /run/kresd/workdir && \
>>  setfacl -m u:kresd:rwx /run/kresd/workdir && \
>>  cd /run/kresd/workdir && \
>>  exec listen -udp::53 \
>>  -tcp::53 \
>>  -tcp:label=tls:853 \
>>  -unix:label=control,mode=0600:/run/kresd/control \
>>  chpst -u kresd -p 1 \
>>  /usr/sbin/kresd
>
> start:
>
>  #!/bin/sh -e
>  install -d -m 0755 -o kresd /run/kresd/workdir
>
> stop:
>
>  #!/bin/sh -e
>  rm -r /run/kresd/
>
> run:
>
>  #!/bin/nosh
>  udp-socket-listen --systemd-compatibility --combine4and6 :: domain
>  tcp-socket-listen --systemd-compatibility --combine4and6 --backlog 2 
> :: domain
>  local-datagram-socket-listen --systemd-compatibility --mode 0666 
> /run/kresd/query.socket
>  local-stream-socket-listen --systemd-compatibility --mode 0600 
> /run/kresd/control
>   ./service
>
> service:
>
>  #!/bin/nosh
>  chdir /run/kresd/workdir
>  softlimit -p 1
>  setuidgid kresd
>  kresd

Thanks, this looks pretty cool.

a couple caveats:

 * i don't see where the label for the sockets is passed in.  how is the
   daemon supposed to know whether to listen on the tcp socket using TLS
   or not?  How is it supposed to know whether the unix domain socket is
   for control or for recursive DNS queries?

 * it looks like this will result in a chain of proceses: nosh → nosh →
   kresd, rather than a single process due to the lack of exec.  or am i
   misunderstanding nosh?


I see you've got debian packages available for nosh, but they aren't in
debian proper.  have you considered putting them into debian?

   --dkg


signature.asc
Description: PGP signature


Re: s6, listen(8), etc.

2016-09-05 Thread Jonathan de Boyne Pollard

Laurent Bercot:


how does the daemon know what fd corresponds to what use?

In the wild, it's generally a for() loop over the passed-in descriptors 
that checks each socket type.  In the wild, only one of any type is 
often the case.


"If AF_INET4 and SOCK_DGRAM, this must be my UDP4 socket."

That's how I patched dnscache and tinydns to work, too.  A simple set of 
socket_is() functions in the Bernstein socket library, and it is off and 
away.




Re: s6, listen(8), etc.

2016-09-05 Thread Jonathan de Boyne Pollard

Daniel Kahn Gillmor wrote:

So i'm hoping that it'll find a taker in one of these more 
toolkit-style supervisor suites.



http://jdebp.eu./Softwares/nosh/#Features

socket services section



Re: s6, listen(8), etc.

2016-09-04 Thread Laurent Bercot

On 01/09/2016 21:12, Daniel Kahn Gillmor wrote:

I think we might be approaching diminishing returns on this thread, so
please don't take offense if i don't reply too much beyond this.


 Are you kidding? We're just getting started. I haven't had a good
design discussion for ages! :D



This doesn't allow for the creation of multiple different sockets
e.g. for a daemon expected to listen on distinct IPv6 and IPv4
addresses, but not on all available addresses.


 Well, hardcoding the fd numbers requires the daemon to use a fixed
number of them, yes. It only works in static cases; as soon as you're
doing anything fancier, you need something more powerful.



I'd want the map the other way around: from number to use case, if i was
going to go for a re-design like this, though i suppose it's roughly
equivalent to have udp=3,udp=4,tcp=5 as long as you don't mind having
repeated keys.  but meh, this is basically equivalent.


 No, because the daemon doesn't care about the numbers, it cares about
the use case. The daemon doesn't want to know what fd 3 is about, it wants
to know what fd it should perform UDP socket operations on.
 If you want to provide several fds for the same use (i.e. a daemon that
listen on several UDP sockets with the same functionality), then you should
give a list of fds. "UDP_FD=3,8" for instance. Or, with LISTEN_FDS_MAP,
something like "udp=3,8:tcp=5".



this seems no more unwieldy (probably less unwieldy) than the convention
to always use FD 6 and FD 7.  what if i wanted to have some other fd
open on those numbers for some other reason?  i'd have to move it out of
the way to use the s6 convention.


 fds 6 and 7 are only used for UCSPI clients, which are a very minor subset
of the programs you'd want to use that mechanism with.
 And yes, it is a bit unwieldy to have hardcoded fd numbers, that's why
I only recommend it for programs that only use a small number of fds -
typically UCSPI clients and servers only use two.
 Fortunately, it's easy to move fds around. The shell redirection
operators are getting so little use these days! And for executable chains,
execline's "fdmove" can be plugged anywhere. Internally, s6-rc makes
heavy use of fdmove.



eh?  on the contrary: if your daemon doesn't need to distinguish between
any of its sockets -- if all sockets are standard listening sockets
(it can still inspect the socket itself to distinguish between datagram
and stream) then it doesn't care about anything but LISTEN_FDs.


 Maybe it's just aesthetics at this point, but I don't like the idea of
having to inspect the fds you're given. If I'm using preopened sockets, I
want to be able to trust the caller to pass me the correct socket types
(and fail loudly if it doesn't). I don't want the caller to tell me
"here's a bunch of fds, you sort them out": that's just laziness.



If the daemon receives some sockets (like a local control socket) that
need to be treated differently, then it needs to look at the map.  Your
proposed LISTEN_FD_MAP looks precisely equivalent to LISTEN_FDNAMES for
this purpose, with only minor syntactic differences.  The non-syntactic
difference, of course, is that multiple daemons written and running
today actually already know how to parse LISTEN_FDNAMES, whether because
they link to libsystemd or do the simple parsing themselves.  if
LISTEN_FD_MAP had gotten there first, i would have made listen(8)
implement that labeling scheme.


 And there are also multiple daemons written and running today that
already know how to read an open fd number from an environment variable,
and that didn't wait for systemd to bring them God's gift to daemon
design. :P

 Following existing practice for interoperation purposes is a dangerous
positive feedback loop: it's only a good thing when the existing practice
is already good. And I don't subscribe to the "A bad convention is
better than no convention at all" point of view: if a convention is bad,
I make it my job to think of a better one instead. This is what we are
doing right now, this is why I love design discussions, and I thank you
for this opportunity.



I'd still call LISTEN_FDS a "convention" and not a "mechanism", fwiw.
I'd be interested in seeing a pointer to anything you write up.  Please
post it here!


 I have started working on it, but I have more urgent stuff on my plate
right now; but I'll definitely keep you informed. Also, since it's the
second wrapper of its kind, there's a chance it won't be the last, so I'm
thinking of gathering those wrappers into a new package, with the theme
"how to make your daemons work with the systemd interfaces without having
to change them to use the systemd interfaces". Good stuff to come! ;)

--
 Laurent



Re: s6, listen(8), etc.

2016-09-01 Thread Daniel Kahn Gillmor
I think we might be approaching diminishing returns on this thread, so
please don't take offense if i don't reply too much beyond this.  I do
appreciate your taking the time to document your thought process here,
though.  thanks!

A couple minor comments:

On Thu 2016-09-01 08:34:18 -0400, Laurent Bercot wrote:
>   I agree with this principle entirely. This is good design. The question
> now becomes: how does the daemon know what fd corresponds to what use?
>
>   The simplest, natural answer, used for instance by UCSPI clients and
> servers, is: the fd numbers are hardcoded, they're a part of the daemon
> interface and that should be documented.
>   So, in your example, the kresd documentation should say something like:
>
>   - fd 3 must be a datagram socket, that's where kresd will read its
> UDP DNS queries from.
>   - fds 4 and 5 must be listening stream sockets, that's where kresd will
> read its TCP DNS queries from. kresd use two sockets for this in order to
> allow one of them to be set up over TLS.
>   - fd 6 must be a listening Unix domain stream socket, that's where kresd
> will read its control messages from.

This doesn't allow for the creation of multiple different sockets
e.g. for a daemon expected to listen on distinct IPv6 and IPv4
addresses, but not on all available addresses.

>   LISTEN_FD_MAP=udp=3,tcp=4,tls=5,control=6

I'd want the map the other way around: from number to use case, if i was
going to go for a re-design like this, though i suppose it's roughly
equivalent to have udp=3,udp=4,tcp=5 as long as you don't mind having
repeated keys.  but meh, this is basically equivalent.

>   Or does it? The API still constrains you: even if you can provide labels,
> you still don't send a map, you send a number of fds and a list of labels.
> So you still have to make sure the fds you send are 3, 4, 5, 6 ! And
> if your "listen" program happens to have fd 3 open when it's launched
> (and there may be very good reasons to have some fd already open when you
> run a daemon), well, it has to overwrite it with the udp socket it opens,
> because that's what the API forces you to do. If I want the daemon to run
> with some open fd that's not explicitly passed via LISTEN_FDS (for instance
> if the daemon doesn't have to know it has it open) then I have to make sure
> that my fd is at least 3+$LISTEN_FDS. Talk about unwieldy.

this seems no more unwieldy (probably less unwieldy) than the convention
to always use FD 6 and FD 7.  what if i wanted to have some other fd
open on those numbers for some other reason?  i'd have to move it out of
the way to use the s6 convention.  Note that i'm not claiming this is
terrible, it's only a minor hassle.  but it's the same minor hassle as
what you're describing here, no?

>   And from the daemon's side? it has to parse the contents of $LISTEN_FDNAMES,
> which is a colon-separated list of labels; that's not really easier than
> parsing my suggested LISTEN_FD_MAP string.

right, it's equivalent.

>   So, LISTEN_FDS doesn't know if it wants to pass a list of hardcoded fd
> numbers, or a map with labels; it ends up doing a bit of both, badly, and
> getting the worst of both worlds.

eh?  on the contrary: if your daemon doesn't need to distinguish between
any of its sockets -- if all sockets are standard listening sockets
(it can still inspect the socket itself to distinguish between datagram
and stream) then it doesn't care about anything but LISTEN_FDs.

If the daemon receives some sockets (like a local control socket) that
need to be treated differently, then it needs to look at the map.  Your
proposed LISTEN_FD_MAP looks precisely equivalent to LISTEN_FDNAMES for
this purpose, with only minor syntactic differences.  The non-syntactic
difference, of course, is that multiple daemons written and running
today actually already know how to parse LISTEN_FDNAMES, whether because
they link to libsystemd or do the simple parsing themselves.  if
LISTEN_FD_MAP had gotten there first, i would have made listen(8)
implement that labeling scheme.

>   Oh, and I haven't entirely given up my argument of political agenda.
> The only reason you could have for designing such a whimsical interface,
> apart from obvious lack of experience in software design, is to encourage
> daemon authors to use the sd_listen_fds_with_names() interface (and so,
> link against libsystemd), because it's too painful to fully implement it
> yourself as a daemon author - you have to handle the case when
> LISTEN_FD_NAMES is set, the case when it's not set, etc. etc.

(i don't think that baseless slights against the authors of other
software advance your cause here) on the technical merits, i really
don't see it as difficult as you're making it out to be.  When this
convention is in use, your daemon already knows whether it needs to
parse LISTEN_FDNAMES, or whether it can get away with just looking at
LISTEN_FDS.  in any case, both will be set.  And there is absolutely no
need to link against libsystemd.


Re: s6, listen(8), etc.

2016-09-01 Thread Jan Bramkamp

On 01/09/16 15:43, Roger Pate wrote:

On Thu, Sep 1, 2016 at 8:34 AM, Laurent Bercot
 wrote:

 OK, now let's have a look at LISTEN_FDS.


I also find these particular implementation details a poor choice.  I
was going to recommend a different environment convention, but then I
saw the pre-existing convention was copied exactly.

If I was Daniel, I'd create something better.  But I'm not sure
there's enough interest/need to warrant it.  (Daemons currently
written to expect LISTEN_FDS could have a chain-loaded conversion
program.)

Not that I'm particularly knowledgeable here; s6's fdholding seems
able to fill this niche already.


FD holding is a very general mechanism and requires a protocol between 
the FD holding daemon and the client(s). A "./run" script can access the 
FD holding daemon, but this isn't the purpose of the systemd style 
socket activation.


Socket activation is a very old idea in Unix and commonly implemented 
the inetd superserver. This works well for forking servers with low 
setup overhead. There several problems with forking one process per 
connection.


 * For some protocols forking a process per request is too much overhead.

 * Some daemons perform expensive setup operations e.g. OpenSSH used to 
generate an ephemeral SSHv1 server key during startup.


A socket requires very few resources compared to a running process 
especially a process offering a non-trivial service yet only the bound 
socket is required for clients to initiate a connection. This tempted 
Apple to not just create and bind sockets in the superserver but also 
accept the (first) connection inside the superserver before they spawn 
the service process. The problem is that now the superserver has to pass 
the bound socket and the accepted connected socket to the service 
process. This requires a protocol between the superserver and the 
service. Both Apple and systemd "strongly recommend" applications to 
link against their libraries resulting in an annoying vendor lock-in.


On a classic Unix server running a few services this is unnecessary 
complexity, but these days most unixoid systems are powered by a single 
Lithium battery cell. Launchd went too far too quickly and the original 
implementation requires Mach IPC. In a launchd world every service is 
always available and the processes implementing it are spawned on 
demand. There is even a transaction concept enabling launchd to reclaim 
resources from cooperating services unless they're inside a transaction. 
This design works well on a laptop or smartphone. It fails spectacularly 
in the face of "evil legacy software" which doesn't follow the "one true 
way".


The systemd APIs look like they try to follow a middle ground, but they 
end up making a mess out of things. Have a look at 
https://ewontfix.com/15/ if want to know more about systemd's design flaws.


Re: s6, listen(8), etc.

2016-09-01 Thread Roger Pate
On Thu, Sep 1, 2016 at 8:34 AM, Laurent Bercot
 wrote:
>  OK, now let's have a look at LISTEN_FDS.

I also find these particular implementation details a poor choice.  I
was going to recommend a different environment convention, but then I
saw the pre-existing convention was copied exactly.

If I was Daniel, I'd create something better.  But I'm not sure
there's enough interest/need to warrant it.  (Daemons currently
written to expect LISTEN_FDS could have a chain-loaded conversion
program.)

Not that I'm particularly knowledgeable here; s6's fdholding seems
able to fill this niche already.


Re: s6, listen(8), etc.

2016-09-01 Thread Laurent Bercot

On 01/09/2016 07:52, Daniel Kahn Gillmor wrote:

I think you might have misunderstood the description of the convention,
actually.  There's no unix domain socket for receiving the descriptors
at all.  Rather, the descriptors are already open and present in the
process.


 OK, after reading your message, then the sd_listen_fds man page, it
appears that I have indeed misunderstood it. My bad. It my defence,
it really is not clear from that page whether the descriptors are already
open in the process that invokes sd_listen_fds(), or whether sd_listen_fds
actually connects to systemd to receive them. I understood the latter, and
I will agree it was my prejudice speaking; the former is much more
reasonable. So let's dive a bit deeper.



exec listen -udp::53 \
-tcp::53 \
-tcp:label=tls:853 \
-unix:label=control,mode=0600:/run/kresd/control \
chpst -u kresd -p 1 \
/usr/sbin/kresd

This means kresd doesn't need to know about dropping privileges, opening
listening ports, or resource constraints at all (listen and chpst take
care of that), but kresd can still retain in-memory state that might be
useful for handling multiple connections with no exec() ever involved.


 I agree with this principle entirely. This is good design. The question
now becomes: how does the daemon know what fd corresponds to what use?

 The simplest, natural answer, used for instance by UCSPI clients and
servers, is: the fd numbers are hardcoded, they're a part of the daemon
interface and that should be documented.
 So, in your example, the kresd documentation should say something like:

 - fd 3 must be a datagram socket, that's where kresd will read its
UDP DNS queries from.
 - fds 4 and 5 must be listening stream sockets, that's where kresd will
read its TCP DNS queries from. kresd use two sockets for this in order to
allow one of them to be set up over TLS.
 - fd 6 must be a listening Unix domain stream socket, that's where kresd
will read its control messages from.

 To me, that approach is good enough. But you could reasonably argue that's
unwieldy. So the next step is to have a map, a simple key-value store that
maps identifiers to fd numbers. And the simplest implementation of a
key-value store is the environment. So, the kresd documentation could say
something like this:

 kresd will read the values of the UDP_FD, TCP_FD, TLS_FD and CONTROL_FD
environment variables. Those variables should contain an integer which
represents an open file descriptor. kresd will use the descriptor in
$UDP_FD to receive DNS queries over a datagram socket. etc. etc.

 That's much friendlier to the person who writes the run script for kresd,
and that's also pretty easy to implement for the kresd author: read an
integer in an environment variable. All in all, it sounds like a good
solution when the daemon has more than 2 or 3 fds to handle.

 But, you say, that's not generic enough a mechanism! A process manager
cannot pass a flock of environment variables to a daemon, the names of
which depend on the daemon entirely! It has to settle on a few standardized
environment variable names.
 Well, first, yes, it definitely can pass a flock of environment variables,
that's what a run script is for. I'm pretty sure systemd even has syntactic
sugar to change the daemon's environment before spawning it. With s6,
you can also store your variable set into the filesystem and read it via
s6-envdir.
 Second, even if you don't want to do that, it's a simple map, and a map
is easily passed as a single variable in the environment, provided you
reserve a separator character. Let's say your process manager will pass
the LISTEN_FD_MAP environment variable to daemons, and labels aren't
allowed to use commas:
 LISTEN_FD_MAP=udp=3,tcp=4,tls=5,control=6
 It's a bit more work for the daemon, but you can still relatively easily
extract a map from labels to fd numbers from a single environment variable.

 OK, now let's have a look at LISTEN_FDS.

 LISTEN_FDS is designed to be usable without LISTEN_FDNAMES, i.e. as a
list. And in that case, you have a single piece of information: the number
of open fds. Which means:
 - the starting fd has to be hardcoded (3)
 - the fds have to be consecutive.
 So here you'd have LISTEN_FDS=4 and the fds would be 3,4,5,6. The daemon
has to hardcode that 3 is udp, 4 is tcp, 5 is tls and 6 is control - it's
exactly as unwieldy for the run script author, and it's less flexible
because neither the daemon nor the script author can even choose what fds
are allocated! The numbers are enforced by the API. This is not good.

 Right, so there's the LISTEN_FDNAMES mechanism to help. With LISTEN_FDNAMES,
we have a map: the daemon gets labels to help it identify the fds. This
avoids any number hardcoding, this makes it more flexible for the run
script author.
 Or does it? The API still constrains you: even if you can provide labels,
you still don't send a map, you send a number of fds and a list of labels.

Re: s6, listen(8), etc.

2016-08-30 Thread Laurent Bercot

On 30/08/2016 22:51, Daniel Kahn Gillmor wrote:

 https://github.com/skarnet/s6/pull/3


 Applied, thanks!



Thanks, once i make it past the angry words, this page has some
interesting ideas to work from.


 My words have all the right in the world to be angry; being calm is an
oppressor's privilege. (Yes, I am serious; neither being angry nor being
serious about saying that systemd is an oppressor disqualifies me as
a valid technical interlocutor.)



i'm sorry to hear you're so inflexible about this, but that's your call,
i guess.


 Read below for a wonderful example of why. Please don't take it as a
personal attack, which it's not, but as criticism of the design of
systemd.



At any rate the LISTEN_FDS convention of how to pass labeled file
descriptors via a small number of environment variables requires no
systemd code whatsoever, and it's described in a relatively simple
document.


 All I can find about it is the sd_listen_fds() man page, which says:
"Internally, ... otherwise, it parses the number passed in the $LISTEN_FDS
environment variable..."
 In other words, this is internal workings of systemd, this is not an
official API. If at some point systemd decides to change how sd_listen_fds()
is implemented, all the other software relying on LISTEN_FDS will just have
to adapt.

 Even if that convention never changes, a bigger issue is that this use
of an environment variable presupposes an architecture that is similar
to systemd. A daemon that uses sd_listen_fds() will connect to some
hardcoded path to a Unix domain socket to receive the descriptors over
(and if it's not hardcoded, it needs to be given in another environment
variable such as NOTIFY_SOCKET), which means the supervision architecture
also has to provide a daemon that transmits the fds over that socket, etc.
etc. In other words, either the supervision architecture looks very much
like systemd, or the protocol is unusable. It's the same issue that
sd_notify() exhibits - and I have no doubt that it would be the same with
other systemd interfaces.

 LISTEN_FDS, just as NOTIFY_SOCKET, may seem very simple and innocuous
protocols at first sight, but when you look a bit deeper, you find that
they are designed to tighten systemd's monopoly: if you have an alternative,
it has to exactly copy systemd's workings in order to be able to correctly
implement the protocols - and at this point, designing an alternative is
simply useless. The author of uselessd banged their head against that
issue for a long time, and then gave up. The line needs to be drawn much
earlier.



 It's a reasonable improvement in flexibility over the
convention of one-pipe-per-process, I/O on 6+7 and 0+1, and it's not
particularly hard to implement.


 It doesn't look hard, but it's treacherous. It's just impossible to
implement in a modular Unixish way, just as the rest of systemd is:
that's exactly what I call "mixing politics and technology" - using
innocent-looking technical protocols to promote systemd's agenda.
 Now you've got a small glimpse of why I'm angry and inflexible.



 So i'm hoping that it'll find a taker
in one of these more toolkit-style supervisor suites.


 s6 already provides a complete set of fd-holding tools.
 If you have a s6-fdholderd process running, you can give it descriptors
via the s6-fdholder-store command, and get descriptors from it via the
s6-fdholder-retrieve command. Those commands are chain-loading, so it's
easy to call them sequentially to put your process in the exact state
you want it, with all the descriptors you need in the right place, before
exec'ing into your daemon. It's how s6-rc works internally.

--
 Laurent



Re: s6, listen(8), etc. (was: [PATCH 1/3] correct typo)

2016-08-30 Thread Daniel Kahn Gillmor
On Tue 2016-08-30 12:25:37 -0400, Laurent Bercot wrote:
> On 30/08/2016 15:20, Daniel Kahn Gillmor wrote:
>> i assume you mean http://www.skarnet.org/software/s6/ .  thanks for the
>> pointer.  I'm looking at that, and it looks like s6's preferred form of
>> user contact is via github (i've just submitted a trivial pull request).
>
>   Um, not at all. If the homepage gave you that impression, then it's not
> clear enough and I should add a note to it. I only use github as a mirror
> for source browsing and downloading.

Well, your earlier e-mail suggested that you don't like reading patches
on mailing lists, and there were two other pull requests that had
already been closed so i made the (apparently wrong) inference.  sorry
for the confusion.

>   The preferred form of user contact for s6 is through this list - you're
> in the right place. :) What did you want to send a PR about?

it's a bugfix to the web page for s6-ioconnect:

 https://github.com/skarnet/s6/pull/3

>   Please don't use the term "socket activation": it is a systemd buzzword
> with vague and confusing semantics. See
>   http://skarnet.org/software/s6/socket-activation.html

Thanks, once i make it past the angry words, this page has some
interesting ideas to work from.  The timing and privilege separation
aspects are still not clear to me yet, but that'll probably come in
time.

>   Daemons that use shared state in RAM generally open their sockets
> themselves.

well, sure.  they also generally daemonize themselves, which is (quite
reasonably) discouraged under a runit or s6 style architecture, though.
And ones that listen on "privileged" ports (below 1024), or who need to
open listening sockets in places that they themselves wouldn't be able
to create sockets generally start as root and then drop privileges after
opening sockets.  some of them don't always drop privileges very
successfully, either :/

I'm looking for supervisors that help me avoid some of that stuff.
systemd is one; runit is another; so (potentially) is s6.

> In any case, I'll probably update s6-ipcserver-socketbinder so it's
> usable with more types of sockets.

cool, thanks!

>   I'm very interested in sharing thoughts about that, but you'll
> probably find that I'm *extremely* reluctant to yield an inch when
> negotiating with ideas and protocols that come from systemd

i'm sorry to hear you're so inflexible about this, but that's your call,
i guess.

> while being open to ideas for improving daemon management under Unix;
> and most of those ideas have been floating around - and sometimes
> implemented in supervision suites - since before systemd was a
> thing. ;)

yep, we're all learning from each other, hopefully.

At any rate the LISTEN_FDS convention of how to pass labeled file
descriptors via a small number of environment variables requires no
systemd code whatsoever, and it's described in a relatively simple
document.  It's a reasonable improvement in flexibility over the
convention of one-pipe-per-process, I/O on 6+7 and 0+1, and it's not
particularly hard to implement.  So i'm hoping that it'll find a taker
in one of these more toolkit-style supervisor suites.

thanks for the discussion,

   --dkg