When a traditional SysV daemon starts, it should execute the following steps as part of the initialization. Note that these steps are
unnecessary for new-style daemons (see below), and should only be implemented if compatibility with SysV is essential.

[...]

6. In the child, call setsid() to detach from any terminal and create an independent session.

7. In the child, call fork() again, to ensure that the daemon can never re-acquire a terminal again.

but compare this to processes started with no vestige of SysV compatibility:

The processes for both rsyslog.service and systemd-journal.service are session leaders (SID = PID).

It seems that if such programs were configured to log to a TTY, they would gain the TTY as a controlling terminal, and receive an unwanted / fatal signal when the TTY is hung up / receives Ctrl+C, respectively. Unless they remember to set O_NOCTTY when opening the TTY file.

It seems this is a little pitfall when writing or converting a program to run as a systemd service w/o any SysV compatibility, if your program supports writing messages to custom files. It does not seem to be pointed out by this doc which advocates the systemd style. The doc rather implies the opposite, by insisting that double-fork is necessary to avoid this on SysV, and then not mentioning this as an issue when describing the steps a native systemd service would use.

Is that correct? Does systemd provide some protection against this I have overlooked, or is the issue pointed out elsewhere in the systemd doc?

Going by that and the answer, this seems to be rather unrelated to the sysv guide quoted above, which is about protecting services that could have accidentally inherited a controlling terminal as opposed to services that deliberately open a TTY themselves. These would have to take those precautions anyway.
– muruJun 1 '18 at 10:41

@muru I have bolded the specific clause.
– sourcejediJun 1 '18 at 12:19

2 Answers
2

You are assuming that it should. On the contrary, consider settings like TTYPath and services like getty@.service. The ability to gain a controlling terminal is actually necessary, in order that service management can encompass TTY login services, which need to do precisely that.

What actually protects against it is the move away from automatic allocation of a controlling terminal at open(), and discarding the old semantics. Or would protect against it. It is not the case on Linux, but on FreeBSD, NetBSD, OpenBSD, and Hurd nowadays the O_NOCTTY flag to open() is entirely superfluous. The only way to acquire a controlling terminal is by explicitly demanding it, with ioctl(…TIOSCTTY). This has actually been the case for approaching a quarter of a century, since the days of 4.4BSD.

In the meantime, the habit to get into on Linux is the habit that has also been the case for a long time, long before systemd: O_NOCTTY everywhere. ☺

(Yes, the GNU and musl C libraries do not give this to you for fopen(). This is one of several reasons that fdopen() is still a useful mechanism.)

Service management with the nosh toolset's service-manager takes a slightly different tack on this. Rather than always make dæmon processes into session leaders, each service being allocated its own kernel session object that then sees no use, only specific services also chain through setsid explicitly; such as ttylogin@* services that use open-controlling-tty, agetty@* services where of course agetty is setting the controlling terminal, and getty@* services. (As noted in the service source, mgetty calls setsid() itself.)

Technically, I did not assume that it should when I wrote the question. The assumption is more that the documentation implies that it should. I could be reading the documentation wrong though, or have written the question wrong, or something.
– sourcejediJun 1 '18 at 13:29

I did consider getty@.service. The documentation around TTYPath includes specific mention of controlling tty. Maybe there's an implication there when you're not using TTYPath, but it didn't feel explicit enough to rule anything out. Actually, if you define your service in terms of controlling a TTY, it seems plausible that systemd would automatically inhibit detaching from a tty (setsid)... if systemd had included such code in the first place.
– sourcejediJun 1 '18 at 13:31

I guess it might be technically possible that the getty shirks the systemd-provided ctty though, before opening the device by itself. The stock systemd getty services tend to confuse me, as they both use TTYPath, and pass the name of the device to the getty. It definitely expects the getty to open the device itself.
– sourcejediJun 1 '18 at 14:06

I see, BSD stopped the automatic allocation of a controlling terminal a few years after the creation of Linux (1994-ish v.s. 1991-ish), and Linux didn't import the change.
– sourcejediJun 1 '18 at 14:21