2

I have xinetd running inside a docker container (base image centos:7) on a rockylinux 9 host machine.

On starting xinetd service in the docker image, it appears to hang. So I used strace, and found the following output, rapidly counting up:

close(181189)                           = -1 EBADF (Bad file descriptor)
close(181190)                           = -1 EBADF (Bad file descriptor)
close(181191)                           = -1 EBADF (Bad file descriptor)
close(181192)                           = -1 EBADF (Bad file descriptor)
close(181193)                           = -1 EBADF (Bad file descriptor)
close(181194)                           = -1 EBADF (Bad file descriptor)
close(181195)                           = -1 EBADF (Bad file descriptor)
close(181196)                           = -1 EBADF (Bad file descriptor)

Running strace xinetd on another Centos 8 host I see the same behavior.

It appears that xinetd is going through all the available file descriptors, past the /proc/sys/fs/file-max (if a limit is configured, it goes past that limit) until it runs out of numbers.

What is happening here? Why would it have this behavior?

Update March 2023:

For those in similar circumstances, based on the answer detailed below, you can set ulimits via docker when running a container. This is also available in docker compose, and in nomad. Unfortunately, it is not available in k8s.

MirroredFate
  • 459
  • 5
  • 9
  • 1
    systemd-init, docker AND xinetd? how many levels of service management do you really need? – anx Feb 22 '23 at 19:23
  • 1
    Until there is some sort of convergence within the service management space, and updates made to decades-old services that have poor, embedded assumptions.... apparently three. – MirroredFate Mar 02 '23 at 19:47

1 Answers1

3

Many traditional daemons do this, as part of their "daemonization" sequence which is meant to avoid inheriting anything from a user's environment, as traditionally (before IPC-oriented init systems such as systemd or Upstart became popular) the administrator would just directly run an /etc/rc.d script from an interactive session, and sometimes would just directly start the daemon binary – which is then supposed to fork/double-fork, re-open stdin/out/err, shake off any controlling ttys, write its own pidfile, and so on.

For example, an old /etc/rc.d/inetd might have been as simple as this:

case $1 in
    start)
        echo -n "Starting inetd..."
        /sbin/inetd
        echo "done."
[...]

But there is no cross-platform method for determining which file descriptors are open. Some Unixes have a syscall such as closefrom(), others allow the process to iterate over /proc/self/fd/[0-9], but some don't have anything better than iterating from 3 all the way to the current RLIMIT_NOFILE value and blindly trying to every possible FD.

The latter is what xinetd does, with the assumption that its NOFILE limit will be somewhere around 1k to 4k at most. (Which was generally the case 20-30 years ago when its startup code was written – it hasn't been changed much since then.)

user1686
  • 10,162
  • 1
  • 26
  • 42